防止长时间运行JavaScript从locking浏览器
我有JavaScript,它执行了大量的计算,以及从DOM读取/写入值。 该页面是巨大的,所以这往往最终locking浏览器长达一分钟(有时更长的IE浏览器)与100%的CPU使用率。
有没有优化JavaScript的资源,以防止这种情况发生(我能find的是如何closuresFirefox的长时间运行的脚本警告)?
如果您可以将计算algorithm转换为可以迭代调用的方法,则可以通过使用setTimeout和一个较短的超时值,以频繁的间隔将控制权释放回浏览器。
例如,像这样的东西…
function doCalculation() { //do your thing for a short time //figure out how complete you are var percent_complete=.... return percent_complete; } function pump() { var percent_complete=doCalculation(); //maybe update a progress meter here! //carry on pumping? if (percent_complete<100) { setTimeout(pump, 50); } } //start the calculation pump();
使用超时。
通过把你的循环的内容放到不同的函数中,并且在setTimeout()中调用它们,超时时间为50左右,那么javascript就会产生对线程的控制,稍后再回来,允许UI得到在看。
这里有一个很好的工作。
前段时间我曾经在博客中介绍过关于浏览器性能的内容 ,但是让我们在这里总结一下与DOM有关的内容。
- 尽可能不要更新DOM。 对内存中的DOM对象进行更改,并将它们仅附加到DOM一次。
- 使用innerHTML。 在大多数浏览器中,它比DOM方法更快。
- 使用事件委托,而不是常规的事件处理。
- 知道哪些电话是昂贵的,并避免它们。 例如,在jQuery中,$(“div.className”)将比$(“#someId”)更昂贵。
然后有一些与JavaScript本身有关:
- 尽可能less地循环。 如果您有一个收集DOM节点的函数,另一个函数处理它们,则循环两次。 相反,将匿名函数传递给收集节点的函数,并在收集节点时处理这些节点。
- 尽可能使用本机function。 例如,forEach迭代器。
- 使用setTimeout让浏览器稍微呼吸一下。
- 对于具有幂等输出的昂贵函数,请caching结果,以便不必重新计算结果。
我的博客还有更多(上面的链接)。
您可以尝试在线程中执行长时间运行计算(请参阅JavaScript和线程 ),尽pipe它们不是很便于携带。
您也可以尝试使用一些Javascript分析器来查找性能瓶颈。 Firebug支持分析JavaScript。
这仍然是一个有点出血的边缘,但Firefox 3.5有这些东西叫Web Workers,我不确定他们在其他浏览器支持。
Resig先生在这里有一篇关于他们的文章: http : //ejohn.org/blog/web-workers/
而模拟退火可能是最简单的例子,如果你注意到当工作线程正在做他们的请求(因此不冻结浏览器)时,旋转的Firefox标志不会冻结。
我的经验是,DOM操作,特别是在IE中,比“核心”JavaScript(循环等)更多的是性能问题。
如果您正在构build节点,那么通过构buildHTMLstring,然后在容器上设置innerHTML,而不是使用像createElement / appendChild这样的DOM方法,IE中的速度要快得多。
你可以尝试缩短代码
$(xmlDoc).find("Object").each(function(arg1) { (function(arg1_received) { setTimeout(function(arg1_received_reached) { //your stuff with the arg1_received_reached goes here }(arg1_received), 0) })(arg1) }(this));
或“for”循环尝试
for (var i = 0 ; i < 10000 ; i = i + 1) { (function(arg1_received) { setTimeout(function(arg1_received_reached) { //your stuff with the arg1_received_reached goes here }(arg1_received), 0) })(arg1_to_send) }
我有同样的问题,我的客户报告这是“杀死页面”的错误。 但是现在我得到了一个最好的解决scheme。 🙂