Как увеличить максимальный стек вызовов в Javascript? - PullRequest
10 голосов
/ 22 марта 2012

У меня есть событие, которое может срабатывать само.Я пытаюсь сделать код максимально эффективным, но он может достигнуть максимального стека вызовов в некоторых случаях, которые находятся вне моего контроля.Это не бесконечный стек, и в какой-то момент он закончится, но иногда он может потерпеть крах до того, как закончится из-за ограничения.

Увеличу ли я количество стеков вызовов, если настрою 2 одинаковых прослушивателя событий и разделю код?Или что я могу сделать?

ОБНОВЛЕНИЕ : это событие DOM (работает только с Webkit, поэтому не заботятся о других браузерах), которое также может изменять DOM на основе некоторыхусловия.Я еще не достиг этого предела, но теоретически это возможно.Я все еще оптимизирую код, чтобы сделать как можно меньше манипуляций с DOM.

ОБНОВЛЕНИЕ 2 : Я включаю пример (не настоящий) пример:

document.addEventListener('DOMSubtreeModified', function(event){

    this.applyPolicy(event);

}, true);

function applyPolicy(event){
    if( typeof event != "undefined" ){
        event.stopPropagation();
        event.stopImmediatePropagation();
    }

    if( !isButtonAllowed ){
        $('button:not(:disabled)').each(function(){

           $(this).attr('disabled', true);

        });
    }
}

Это всего лишь пример кода, но даже в этом случае, если вы скажете, что кнопки, скажем, сотни, стек вызовов будет также и в сотнях.Обратите внимание, что если вы используете $('button').attr('disabled', true);, это вызовет проблему стека вызовов, потому что jQuery будет пытаться бесконечно изменять DOM.

Ответы [ 6 ]

6 голосов
/ 22 марта 2012

Хотя может показаться, что вам, возможно, потребуется переосмыслить некоторый код, одной из возможностей будет поставить рекурсивный вызов в setTimeout через некоторый заданный интервал.Это позволяет начать новый стек вызовов.

Возьмите этот пример ...

var i = 0;

function start() {
    ++i;
    var is_thousand = !(i % 1000);

    if (is_thousand)
        console.log(i);

    if (i >= 100000)
        return; // safety halt at 100,000
    else
        start()
}

Он просто регистрируется на консоли через каждый интервал 1,000.В Chrome он превышает стек где-то в диапазоне 30,000.

DEMO: http://jsfiddle.net/X44rk/


Но если вы переделаетеэто так ...

var i = 0;

function start() {
    ++i;
    var is_thousand = !(i % 1000);

    if (is_thousand)
        console.log(i);

    if (i >= 100000) // safety halt at 100,000
        return;
    else if (is_thousand)
        setTimeout(start, 0);
    else
        start();
}

Теперь при каждом 1,000 функции будет разрешено возвращаться, и следующий вызов будет выполняться асинхронно, начиная новый стек вызовов.

Обратите внимание, что это предполагает, что функция эффективно завершается при выполнении рекурсивного вызова.

Также обратите внимание, что у меня есть условие, чтобы остановиться на 100,000, поэтому мы не бесконечны.

ДЕМО: http://jsfiddle.net/X44rk/1/

6 голосов
/ 22 марта 2012

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

Если вы столкнулись с этим, это показатель того, что ваш код остро нуждается в реорганизации

0 голосов
/ 22 марта 2012

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

За исключением реорганизации вашего кода таким образом, чтобы никакой сторонний код не ожидал (или не был предоставлен) доступ к DOM, мое решение было бы следующим:

  1. Дублируйте ваш DOM в скрытый iframe.
  2. Песочница - сторонний код в указанном iframe.
  3. При любом изменении DOM в iframe проверьте iframe на наличие различий между двумя деревьями DOM. Если изменение передает белый список , перетащите его в свой реальный DOM (повторно присоедините обратные вызовы событий и т. Д.).
  4. Скопируйте структуру "реального" DOM ​​после обновлений в iframe DOM, удалив из него все конфиденциальные данные.

Вы бы по-прежнему проверяли событие DOM в iframe, но на своей "реальной" странице вы этого не сделали бы, поэтому не можете войти в бесконечный цикл.

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

0 голосов
/ 22 марта 2012

Если вы достигнете предела стека вызовов, вы почти наверняка получите рекурсивный ряд событий. События полагаются на стек, поэтому они действительно не лучший способ реализации цикла. В языке без исключения хвостовых вызовов единственным реальным вариантом является использование стандартных конструкций цикла, таких как for / in.

0 голосов
/ 22 марта 2012

Вы не можете , они зависят от браузера и, откровенно говоря, имеют достаточно широкий диапазон, поэтому не нужно беспокоиться об этом IMO.

0 голосов
/ 22 марта 2012

Размер стека вызовов и детали реализации будут зависеть от среды JavaScript, в которой выполняется ваш код. Даже если вы можете манипулировать использованием стека для запуска в средах, которые вас сейчас интересуют, есть большой шанс, что код, требующий стека, потерпит крахпри запуске в среде с другим размером стека.

Любая рекурсивная программа может быть переписана как итеративная.Подумайте, можете ли вы сделать это в вашем случае.См .:

Путь от рекурсии к итерации

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