简体   繁体   中英

How to increase the maximum call stack in Javascript?

I have an event, which can fire itself. I try to make the code as efficient as possible, but it can hit maximum call stack in some circumstances, which are out of my control. It's not an infinite stack and it will end at some point, but sometimes it can potentially crashe before it finishes because of the limit.

Will I increase the number of call stack if I set up 2 similar event listeners and split the code? Or what can I do?

UPDATE : It's on DOM change event (working with Webkit only, so don't care about other browsers), which can also modify the DOM based on some conditions. I haven't really hit that limit yet, but theoritically, it potentially can. I'm still optimizing the code to make as less DOM manipulations as possible.

UPDATE 2 : I'm including sample (not real) example:

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);

        });
    }
}

This is just a sample code, but even in this case, if you have say 100s of buttons, the call stack will be in 100s too. Note that if you use $('button').attr('disabled', true); , this will cause call stack problem, because jQuery will be trying to modify the DOM infinitely.

For any browser the maximum call stack runs well in the thousands. You should try to optimize the code, having a huge call stack is not good for speed and memory.

If you're running into this, it's an indicator your code is in dire need of reorganization

While it sounds like you may need to rethink some code, one possibility would be to put a recursive call in a setTimeout at some given interval. This allows you to begin a new call stack.

Take this example...

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()
}

It just logs to the console at every interval of 1,000 . In Chrome it exceeds the stack somewhere in the 30,000 range.

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


But if you rework it like this...

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();
}

Now at every 1,000 , the function will be allowed to return and the next call will be made asynchronously, starting a new call stack.

Note that this assumes that function is effectively ended when the recursive call is made.

Also note that I have a condition to stop at 100,000 so we're not infinite.

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

The size of the callstack and implementation details will depend on the JavaScript environment your code is running in. Even if you can manipulate stack usage to run in environments you care about now, there's a great chance that stack-hungry code will crash when run in an environment that provides a different stack size.

Any recursive program can be rewritten as an iterative one. Consider if you can do that in your case. See:

Way to go from recursion to iteration

不能 ,他们是浏览器依赖,坦率地说,他们有相当广泛的范围,所以没有必要担心IMO。

If you're hitting the call stack limit, you almost certainly have a recursive series of events. Events rely on a stack, so they're really not the best way of implementing a loop. In a language without tail call elimination, your only real option is to use the standard loop constructs like for/in.

After finding out that you're censoring third-party code that may be rendering elements you don't want rendered, I understand the real root problem: Blacklists never work on untrusted code , eventually some code will get past your blacklist and you're done for.

Outside of rearchitecting your code such that no third-party code expects (or is given) access to the DOM, my solution would be as follows:

  1. Duplicate your DOM into a hidden iframe.
  2. Sandbox the third party code in said iframe.
  3. On any DOM change in the iframe, inspect the iframe for differences between the two DOM trees. If the change passes a whitelist , pull it up into your real DOM (re-attaching event callbacks and so on).
  4. Copy the structure of the "real" DOM after the updates into the iframe DOM, scrubbing any sensitive data from it in the process.

You'd still check on a DOM event in the iframe, but you wouldn't in your "actual" page, so you can't enter an infinite loop.

This is assuming that you really can't trust your third party code to do what it should do. If it's just vendor incompetence, forget the scrubbing portion, but stick with the whitelist instead of the blacklist, anyways.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM