setTimeout如何防止潜在的stackoverflow

时间:2016-06-02 13:13:36

标签: javascript javascript-events stack-overflow

一个例子:

var list = readHugeList();

var nextListItem = function() {
    var item = list.pop();

    if (item) {
        setTimeout( nextListItem, 0);
        // ^^^^^^^^ this line
    }
};

如何使用setTimeout阻止潜在的堆栈溢出?我理解事件队列的概念以及堆栈,但是我很难连接这两个。

2 个答案:

答案 0 :(得分:2)

设置超时不会导致堆栈溢出,因为它是异步的。它只会将回调放入事件队列而不会阻止执行。

在第一种情况下:

setTimeout只是将回调放入事件队列,而父函数在没有占用堆栈的情况下退出。   
即使超时为0 ms,它也会在下一个事件循环中被调用,因此不会阻止执行中的代码

var nextListItem = function() {
    var item = list.pop();

    if (item) {
         setTimeout( nextListItem, 0);
    }
};

在第二种情况下:

  父调用子函数将新条目放入堆栈,即使父项未从堆栈中清除    最终,更多的递归调用会破坏堆栈。

var nextListItem = function() {
        var item = list.pop();

        if (item) {        
           nextListItem();
        }
    };

答案 1 :(得分:1)

考虑setTimeout(, 0)安排一个函数在此终止后运行。 nextListItem()不会被递归调用,而是由JS环境再次调用。

如果你执行var r() = function() { r(); };,函数会自行调用并且会溢出堆栈。如果您执行var r() = function() { setTimeout(r, 0); };,那么r()将被安排在r()终止后运行,它将永久运行。

这是使用setTimeout(, 0)代替whilefor循环列表的原因。它允许浏览器在下次调用nextListItem之前处理其他事件。如果列表很长,这可以避免长时间阻止浏览器。另一方面,如果nextListItem正在操纵DOM,那么它比在一次执行中慢得多。