Рекурсия в js setTimeout как это работает? а почему это работает? - PullRequest
0 голосов
/ 06 мая 2020
function printNumbers(from, to) {
  let current = from;

  function go() {
    alert(current);
    if (current < to) {
      setTimeOut(go, 1000); //recursion to function go() 
    }
    current++; // because of recursion execution should not reach this point 
  }, 1000);
}

printNumbers(5, 10);

Объясните, пожалуйста, почему ^ current ++ ^ работает сразу? но из-за рекурсии работать не должно. не так ли? объясните пожалуйста, кто понимает, как это работает и почему

Ответы [ 2 ]

4 голосов
/ 06 мая 2020

setTimeout не блокирует. Он помещает функцию в очередь для вызова по прошествии некоторого времени. Остальная часть функции по-прежнему выполняется без пауз.

Нет оператора return или чего-либо еще, что остановило бы механизм JS от достижения оператора current++;.

0 голосов
/ 06 мая 2020

Чтобы дополнить ответ Квентина, эта строка setTimeout(go, 1000) (FYI, setTimeout - правильное написание, а не setTimeOut) на самом деле не выполняет никакой рекурсии. Он передает функцию go, вызываемую через 1000 мс в событии l oop после опустошения стека (тот же стек, который может выполнять рекурсию и переполнение). Случайно, что все это происходит в той же функции, которая передается в качестве параметра тайм-ауту, что делает его визуально рекурсивным.

Происходит то, что строка setTimeout запускается и добавляет функцию go к событию l oop и гарантирует задержку не менее 1000 мс. Затем выполняется остальная часть синхронного кода, включая остальную часть go и current++;. Позже, когда стек пуст, задачи на l oop выполняются по порядку, включая go (при условии, что таймер 1000 мс истек).

Это объясняет, почему такой код, как:

(function run() {
  requestAnimationFrame(run);
  // do stuff
})();

никогда не переполняет стек: на самом деле это не рекурсия и каждый кадр вызова уничтожается до того, как произойдет следующий вызов.

В стороне, может показаться удивительным, что

(function run() {
  requestAnimationFrame(run);
  // do stuff
})();

и

(function run() {
  // do stuff
  requestAnimationFrame(run);
})();

ведут себя примерно одинаково. Причина в том, что следующий обратный вызов run гарантированно выполнится после того, как весь синхронный код (текущий вызов run и все остальное в стеке вызовов) завершит выполнение, поэтому это не похоже на то, что местоположение вызывает блок в синхронном исполнении и дочерний вызов выполняет работу, как в случае с рекурсией.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...