我有一个可以解雇的事件。我尝试使代码尽可能高效,但在某些情况下它可以达到最大调用堆栈,这是我无法控制的。它不是一个无限的堆栈,它会在某个时刻结束,但有时它可能会因为极限而在它完成之前崩溃。
如果我设置了2个类似的事件监听器并拆分代码,我会增加调用堆栈的数量吗?或者我该怎么办?
UPDATE :它是关于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);
});
}
}
这只是一个示例代码,但即使在这种情况下,如果您说100个按钮,调用堆栈也将在100秒内。请注意,如果使用$('button').attr('disabled', true);
,这将导致调用堆栈问题,因为jQuery将尝试无限地修改DOM。
答案 0 :(得分:6)
对于任何浏览器,最大调用堆栈运行数千。你应该尝试优化代码,拥有一个巨大的调用堆栈对速度和内存不利。
如果您遇到此问题,则表明您的代码迫切需要重组
答案 1 :(得分:6)
虽然听起来你可能需要重新考虑一些代码,但有一种可能性是在某个给定的时间间隔内在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
,所以我们不是无限的。
答案 2 :(得分:0)
callstack的大小和实现细节将取决于运行代码的JavaScript环境。即使你可以操作堆栈使用在你现在关心的环境中运行,堆栈饥饿的代码很可能会崩溃在提供不同堆栈大小的环境中运行时。
任何递归程序都可以重写为迭代程序。考虑一下你是否可以在你的情况下这样做。参见:
答案 3 :(得分:0)
你不能,他们依赖于浏览器,而且坦率地说他们有很广泛的范围,因此无需担心IMO。
答案 4 :(得分:0)
如果你达到了调用堆栈限制,你几乎肯定会有一系列递归事件。事件依赖于堆栈,因此它们实际上不是实现循环的最佳方式。在没有尾部调用消除的语言中,您唯一真正的选择是使用标准循环结构,如for / in。
答案 5 :(得分:0)
在发现您正在审查可能呈现您不想呈现的元素的第三方代码后,我了解真正的根本问题:黑名单从不处理不受信任的代码,最终有些代码会通过你的黑名单而你已经完成了。
在重新架构代码之外,没有第三方代码期望(或被授予)访问DOM,我的解决方案如下:
您仍然会检查iframe中的DOM事件,但您不会在“实际”页面中,因此无法进入无限循环。
这假设你真的不能信任你的第三方代码来做它应该做的事情。如果它只是供应商的无能,忘记擦洗部分,但坚持使用白名单而不是黑名单,无论如何。