Что происходит при выполнении рекурсивной функции без условия выхода
Что проверяют
Понимаете ли вы, что стек вызовов конечен, и отличаете ли переполнение стека от намертво занятого цикла событий. Для фронтендера это ещё и умение прочитать ошибку в консоли и найти цикл в обходе дерева компонентов или DOM.
Как отвечать
Каждый вызов кладёт в стек кадр: аргументы, локальные переменные, адрес возврата. Без условия выхода кадры копятся, пока движок не упрётся в свой лимит, и тогда выбрасывается RangeError: Maximum call stack size exceeded. Это обычная ошибка, она ловится через try/catch, вкладка при этом не умирает.
function walk(node) {
return walk(node.parentNode); // выхода нет, кадры копятся
}
try { walk(document.body); } catch (e) {
console.log(e instanceof RangeError); // true
}Лимит не фиксирован: он зависит от движка и от размера кадра, поэтому функция с десятком локальных переменных упадёт на меньшей глубине, чем пустая. Называть конкретное число не надо.
Дальше стоит развести два случая. Синхронная рекурсия рвёт стек. Рекурсия через setTimeout, queueMicrotask или await стек не растит вовсе, потому что каждый шаг стартует с пустого стека: такой код не упадёт никогда, он просто съест процессор. Бесконечная цепочка микрозадач вдобавок не даст дойти до отрисовки, и вкладка замрёт без единой ошибки в консоли.
Лечится это явным условием выхода, счётчиком глубины как страховкой, а для глубоких деревьев переходом на итерацию с собственным стеком в массиве.
Где спотыкаются
Называют ошибку StackOverflowError. Это имя из Java, в браузере тип другой, и от неправильного имени зависит, найдёт ли человек нужное место в логах мониторинга.
Второе: рассчитывают, что хвостовой вызов будет оптимизирован. В спецификации языка хвостовые вызовы описаны, но в основных движках не реализованы, так что return f(x) кадр не переиспользует.
Третье: считают, что любая бесконечная рекурсия обязательно даст исключение. Две функции, зовущие друг друга через промисы, вешают страницу молча, и отладчик покажет короткий стек, по которому причина не видна.