一个例子:
var list = readHugeList();
var nextListItem = function() {
var item = list.pop();
if (item) {
setTimeout( nextListItem, 0);
// ^^^^^^^^ this line
}
};
如何使用setTimeout阻止潜在的堆栈溢出?我理解事件队列的概念以及堆栈,但是我很难连接这两个。
答案 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)
代替while
或for
循环列表的原因。它允许浏览器在下次调用nextListItem
之前处理其他事件。如果列表很长,这可以避免长时间阻止浏览器。另一方面,如果nextListItem
正在操纵DOM,那么它比在一次执行中慢得多。