防止长时间运行的javascript锁定浏览器

时间:2009-03-23 09:45:21

标签: javascript

我有JavaScript执行大量计算以及从DOM读取/写入值。该页面非常庞大,因此这通常会导致浏览器长达一分钟(使用IE时更长),CPU使用率达到100%。

是否有任何资源可以优化JavaScript以防止这种情况发生(我所能找到的是如何关闭Firefox长时间运行的脚本警告)?

7 个答案:

答案 0 :(得分:48)

如果您可以将计算算法转换为可以迭代调用的内容,则可以使用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();

答案 1 :(得分:8)

使用超时。

通过将循环的内容放入单独的函数中,并使用超时50左右的setTimeout()调用它们,javascript将产生对线程的控制并在稍后返回,允许UI看看。

有一个很好的工作here

答案 2 :(得分:4)

前段时间我曾在博客上发表过关于in-browser performance的文章,但请允许我在这里总结一下与DOM相关的内容。

  • 尽可能不经常更新DOM。对内存中的DOM对象进行更改,并仅将它们附加到DOM。
  • 使用innerHTML。在大多数浏览器中,它比DOM方法更快。
  • 使用事件委派而不是常规事件处理。
  • 知道哪些电话很贵,并避免使用它们。例如,在jQuery中,$(“div.className”)将比$(“#someId”)更昂贵。

然后有一些与JavaScript本身有关:

  • 尽可能少地循环。如果您有一个收集DOM节点的函数和另一个处理它们的函数,那么您将循环两次。相反,将匿名函数传递给收集节点的函数,并在收集节点时处理它们。
  • 尽可能使用本机功能。例如,forEach iterators。
  • 使用setTimeout让浏览器偶尔呼吸一次。
  • 对于具有幂等输出的昂贵功能,请缓存结果,以便您不必重新计算它。

我的博客上还有更多内容(上面的链接)。

答案 3 :(得分:2)

这仍然有点前沿,但Firefox 3.5有这些称为Web Workers的东西,我不确定他们在其他浏览器中的支持。

先生。 Resig在这里有一篇文章:http://ejohn.org/blog/web-workers/

Simulated Annealing可能是最简单的例子,如果您注意到当工作线程正在执行请求时,旋转的Firefox徽标不会冻结(因此不会冻结浏览器)。

答案 4 :(得分:1)

您可以尝试在线程中执行长时间运行的计算(请参阅JavaScript and Threads),尽管它们不是非常便携。

您也可以尝试使用一些Javascript探查器来查找性能瓶颈。 Firebug支持对javascript进行分析。

答案 5 :(得分:1)

我的经验是,DOM操作(尤其是在IE中)比“核心”JavaScript(循环等)更具有性能问题。

如果您正在构建节点,那么在IE中通过构建HTML字符串然后在容器上设置innerHTML而不是使用DOM方法(如createElement / appendChild)来实现这一点要快得多。

答案 6 :(得分:0)

您可以尝试通过

缩短代码
 $(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));

或&#34; for&#34;循环尝试

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)
}

我遇到了同样的问题,而我的客户报告的这个问题是&#34; Kill page&#34;错误。但是现在我juz得到了最好的解决方案。 :)