setTimeout 如何防止潜在的 stackoverflow

How does setTimeout prevent potential stackoverflow

一个例子:

var list = readHugeList();

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

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

setTimeout 的使用如何防止此处潜在的 Whosebug?我了解事件队列和堆栈的概念,但我很难将两者联系起来。

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

第一种情况:

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

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

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

第二种情况:

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

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

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

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

使用 setTimeout(, 0) 而不是 whilefor 来遍历列表是有原因的:它允许浏览器在下一次调用 [= 之前​​处理其他事件19=]。如果列表很长,这可以避免长时间阻塞浏览器。另一方面,如果 nextListItem 正在操纵 DOM,它比一次操作要慢得多。