1

1. Обычная рекурсия.

stack1 stack2

function pow(x, n) {
  if (n != 1) {
    return x * pow(x, n - 1);
  } else {
    return x;
  }
}

console.log( pow(2, 3) );

2. Рекурсия с использование метода setTimeout.

stack3 stack4

var timerId = setTimeout(function tick(a) {
  if ( 0 < a ) {
    console.log( "тик" );
    timerId = setTimeout(tick, 2000, a - 1);
  } else {
    clearInterval(timerId);
  }
}, 2000, 5);

console.log(window);

На втором изображении выделилась 4 строка, ибо я попробовал выбрать определенный вызов в stack, но меня не переместило в него, и все так же показывает последнее контекст. Еще я обратил внимание что в Call Stack указано setTimeout(async).

3. Попробовал реализовать рекурсию как в первом примере с использованием setTimeout.

setTimeout(function tick(a) {
  if (0 < a) {
    console.log("тик");
    return 2 * setTimeout(tick, 2000, a - 1);
  } else {
    return 123;
  }
}, 2000, 2);

console.log(window);

Я хотел сделать глубокую рекурсию через setTimeout, и посмотреть будет ли выход из нее, но этого не произошло.

Итог:

1. С первым примером все ясно.

2. Здесь мне не понятно зачем нужны стеки, если их нельзя просмотреть.

3. В этом примере хотел сделать рекурсию через setTimeout частью выражения, что бы потом вернуть значение через стек, но этого не произошло, так как сборщик мусора все зачистил. Я предполагаю, что как только таймер перестает быть актуальным, то сборщик мусора сразу ее чистит, но мне все равно не понятно почему он игнорирует тот факт, что вызов был в контексте выражения return 2 * setTimeout(tick, 2000, a - 1);, и оно по идеи ждем результата как в первом пункте. Вот более наглядный пример в статье.

P.S: В третьем пункте итогов было заблуждение, и в следствии он полностью ошибочный:

3. В этом примере хотел сделать рекурсию через setTimeout частью выражения, что бы потом вернуть значение через стек, но этого не произошло, так как сборщик мусора все зачистил. Я предполагаю, что как только таймер перестает быть актуальным, то сборщик мусора сразу ее чистит, но мне все равно не понятно почему он игнорирует тот факт, что вызов был в контексте выражения return 2 * setTimeout(tick, 2000, a - 1);, и оно по идеи ждем результата как в первом пункте. Вот более наглядный пример в статье.

return 2 * setTimeout(tick, 2000, a - 1); возвращает id - числовой идентификатор таймера, но по мима получения id опять происходит вызов.

  • "вызов был в контексте выражения return 2 * setTimeout(tick, 2000, a - 1);" - это что значит? В случаях с setTimeout нет никакого стэка. –  Nov 07 '17 at 03:00
  • Я хотел этим сказать, что выражение ждем результата вызова setTimeout(tick, 2000, a - 1), а значит стек не должен очиститься пока этот вызов не вернет что либо, но так как тут используется метод setTimeout, то и работает это возможно по другому, по этому и задал вопрос, что бы пояснили. На счет стека у setTimeout, я глаголил исходя увиденного в консоли, а в ней он есть. – Виталик Черный Nov 07 '17 at 03:19
  • @Igor Может тут и нет как таковой рекурсии в том смысле, что функция не сама себя вызывает, а это делает метод setTimeout. – Виталик Черный Nov 07 '17 at 03:25
  • 2
    Какой смысл команды return внутри функции, поданной в setTimeout? Куда она что-то возвращает? Никакого результата setTimeout не ждет. Обдумайте понятие "асинхронность", помедитируйте. –  Nov 07 '17 at 04:28
  • 1
    @Igor вы обратили внимание, что мы находимся на площадке где люди задают вопросы? Я думаю мне не надо продолжать свою мысль. Можно по конкретней на счет асинхронности. По поводу смысла, то что бы что - то понять, надо поэкспериментировать и разобраться. Не просто так люди проводят опыты. – Виталик Черный Nov 07 '17 at 05:47

0 Answers0