2016-08-31 4 views
0

Я реализовал функцию, которая рекурсивно решает. Потому что иногда нужно делать асинхронно, я не могу использовать простой цикл /while и должен использовать рекурсивные вызовы функций.Предотвращение InternalError: слишком много рекурсии

В очень абстрактном фрагменте это будет означать следующее:

function doStuff(){ 
    // async or sync things -> depends on several circumstances 
    doStuff(); 
} 
doStuff(); 

Это прекрасно работает. Но, как и следовало ожидать, это вызывает проблемы, когда предел максимального рекурсивного вызова превышен. Иногда мне нужно обрабатывать более 25 000 вызовов, что вызывает InternalError: too much recursion в последнем Firefox (50.0a2).

Я обнаружил, что ловить InternalError и повторно вызвав функцию обратного вызова с тайм-аут работы:

function doStuff(){ 
    // async or sync things -> depends on several circumstances 
    try{ 
     doStuff(); 
    } catch(e if e instanceof InternalError){ 
     setTimeout(function(){ 
      doStuff(); 
     }.bind(this), 25); 
    } 
} 
doStuff(); 

Но это выглядит Hacky и некрасиво. Поэтому я спрашиваю себя, каким будет предпочтительный способ обхода этой ситуации - когда вы не можете обрабатывать вещи в цикле и использовать рекурсивные вызовы функций?

+0

Использовать цикл, поскольку устранение длинных хвостовых вызовов не реализовано в текущих браузерах. Обратите внимание, что циклы столь же выразительны, как и рекурсия хвоста, и петли со своей собственной структурой данных стека столь же выразительны, как и не хвостовая рекурсия. Не используйте 'setTimeout'. – ftor

+0

1. Почему бы не использовать 'setTimeout'? Я знаю, что это уродливо, но что это за недостатки? 2. Я не могу использовать обычный цикл, поскольку мне нужно запустить асинхронный код через некоторое время. Цикл будет продолжать работать ... – dude

+0

'setTimeout' невероятно медленный. Однако я не понимаю ваш псевдокод. 'doStuff' не принимает никаких аргументов и ничего не возвращает. Рекурсивный случай блокируется. Он ведет себя точно как обычный цикл. А как насчет базового случая? – ftor

ответ

1

Преобразовать код в асинхронный. В этом случае ваш столбец не будет глубоким

function doStuff(){ 
    setTimeout(doStuff, 0); 
} 
doStuff(); 
+0

Да, это то, что я тоже узнал (см. Вопрос). Но разве это не плохая практика? Тайм-ауты всегда являются сигнальными колокольчиками для меня – dude

+0

Если вы должны использовать рекурсию с таким глубоким стоп-сигналом, то я вижу преобразование только в asyc. Его также не блокирует ваш пользовательский интерфейс (но я думаю, что это медленнее, чем пример синхронизации). почему вы не можете использовать циклы? – Maxx

+0

Хорошо, спасибо. Подождем несколько часов, чтобы убедиться, что лучшего подхода нет. – dude

Смежные вопросы