У меня есть рекурсивная функция с асинхронным интерфейсом, который, скорее всего, превысит пределы глубины стеки при вызове:Как ловушка переполнение стека ошибки
function f(x, cb) {
if (x === 0) {
cb();
} else {
f(x - 1, cb);
}
}
f(1e6, function() {
console.log('done');
}); // BOOM
(и да, она должна быть рекурсивными, переписыванием, чтобы быть итеративным является нежизнеспособны).
я могу решить эту проблему, выполнив рекурсивный вызов асинхронно (например, с помощью setTimeout
или window.postMessage
, которая якобы быстрее):
function f(x, cb) {
if (x === 0) {
cb();
} else {
setTimeout(function() {
f(x - 1, cb);
}, 0);
}
}
f(1e6, function() {
console.log('done');
}); // ok
Но это значительно медленнее. Поэтому я хочу выполнить асинхронный вызов только тогда, когда он в противном случае вызовет переполнение стека. Что-то вроде
function f(x, cb) {
if (x === 0) {
cb();
} else {
if (getCurrentStackDepth() == getMaxStackDepth() - 42)
setTimeout(function() {
f(x - 1, cb);
}, 0);
} else {
f(x - 1, cb);
}
}
}
или, если это не представляется возможным, по крайней мере, определить, когда происходит переполнение, и повторите попытку асинхронно. Что-то по строкам
function f(x, cb) {
if (x === 0) {
cb();
} else {
try {
f(x - 1, cb);
} catch (e) {
if (isStackOverflowError(e)) {
setTimeout(function() {
f(x - 1, cb);
}, 0);
} else {
throw e;
}
}
}
}
Как это можно сделать? Решение через Function.prototype.caller
неприемлемо, так как я в строгом режиме es5-es6. Я бы предпочел портативное решение, но на самом деле он нужен только для хром.
Гораздо проще переписать рекурсию как цикл. И да, вы сказали, что это должно быть рекурсивным, но когда вы используете 'setTimeout', это не будет рекурсивным. – Kenney
@ Kenney это пример, у меня на самом деле около десятка взаимно-рекурсивных асинхронных функций ветвления. –
Хорошо. Прибегнуть к 'setTimeout', чтобы избежать stackoverflow - это плохое решение, IMHO. Ваша исходная функция в основном сводится к 'for (; x> 0; x--) {}; CB(); '. (Кстати, вы понимаете, что ваша верхняя функция не является асинхронной?) – Kenney