简体   繁体   English

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

[英]Prevent long running javascript from locking up browser

I have JavaScript which performs a whole lot of calculations as well as reading/writing values from/to the DOM.我有 JavaScript 执行大量计算以及从/向 DOM 读取/写入值。 The page is huge so this often ends up locking the browser for up to a minute (sometimes longer with IE) with 100% CPU usage.该页面很大,因此这通常会以 100% 的 CPU 使用率锁定浏览器长达一分钟(IE 有时会更长)。

Are there any resources on optimising JavaScript to prevent this from happening (all I can find is how to turn off Firefox's long running script warning)?是否有任何资源可以优化 JavaScript 以防止这种情况发生(我只能找到如何关闭 Firefox 的长时间运行脚本警告)?

if you can turn your calculation algorithm into something which can be called iteratively, you could release control back the browser at frequent intervals by using setTimeout with a short timeout value.如果你可以将你的计算算法变成可以迭代调用的东西,你可以通过使用带有短超时值的setTimeout以频繁的间隔释放控制权。

For example, something like this...例如,像这样的事情......

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();

Use timeouts.使用超时。

By putting the content of your loop(s) into separate functions, and calling them from setTimeout() with a timeout of 50 or so, the javascript will yield control of the thread and come back some time later, allowing the UI to get a look-in.通过将循环的内容放入单独的函数中,并从 setTimeout() 以 50 左右的超时时间调用它们,javascript 将让出对线程的控制权并在一段时间后返回,从而允许 UI 获得在看。

There's a good workthrough here . 这里有一个很好的解决方法。

I had blogged about in-browser performance some time ago, but let me summarize the ones related to the DOM for you here.前段时间我曾写过一篇关于浏览器内性能的博客,但让我在这里为你总结一下与 DOM 相关的内容。

  • Update the DOM as infrequently as possible.尽可能不频繁地更新 DOM。 Make your changes to in-memory DOM objects and append them only once to the DOM.对内存中的 DOM 对象和 append 只对 DOM 进行一次更改。
  • Use innerHTML.使用内部 HTML。 It's faster than DOM methods in most browsers.在大多数浏览器中,它比 DOM 方法更快。
  • Use event delegation instead of regular event handling.使用事件委托而不是常规事件处理。
  • Know which calls are expensive, and avoid them.知道哪些电话是昂贵的,并避免它们。 For example, in jQuery, $("div.className") will be more expensive than $("#someId").例如,在 jQuery 中,$("div.className") 将比 $("#someId") 更昂贵。

Then there are some related to JavaScript itself:然后还有一些与 JavaScript 本身相关的:

  • Loop as little as possible.尽可能少循环。 If you have one function that collects DOM nodes, and another that processes them, you are looping twice.如果你有一个 function 收集 DOM 节点,另一个处理它们,你循环两次。 Instead, pass an anonymous function to the function that collects the nodes, and process the nodes as your are collecting them.相反,将匿名 function 传递给收集节点的 function,并在收集节点时处理节点。
  • Use native functionality when possible.尽可能使用本机功能。 For example, forEach iterators.例如,forEach 迭代器。
  • Use setTimeout to let the browser breathe once in a while.使用 setTimeout 让浏览器偶尔呼吸一下。
  • For expensive functions that have idempotent outputs, cache the results so that you don't have to recompute it.对于具有幂等输出的昂贵函数,缓存结果,这样您就不必重新计算它。

There's some more on my blog (link above).我的博客上还有更多内容(上面的链接)。

This is still a little bit bleeding edge, but Firefox 3.5 has these things called Web Workers, I'm not sure about their support in other browsers though.这仍然有点前沿,但 Firefox 3.5 有这些称为 Web Workers 的东西,不过我不确定它们在其他浏览器中的支持。

Mr. Resig has an article on them here: http://ejohn.org/blog/web-workers/ Resig 先生在这里有一篇关于它们的文章: http://ejohn.org/blog/web-workers/

And the Simulated Annealing is probably the simplest example of it, if you'll notice the spinning Firefox logo does not freeze up, when the worker threads are doing their requests (thus not freezing the browser).模拟退火可能是最简单的例子,如果你注意到旋转的 Firefox 标志没有冻结,当工作线程正在执行他们的请求时(因此不会冻结浏览器)。

My experience is that DOM manipulation, especially in IE, is much more of an issue for performance than "core" JavaScript (looping, etc.).我的经验是 DOM 操作,尤其是在 IE 中,比“核心”JavaScript(循环等)更成为性能问题。

If you are building nodes, it is much faster in IE to do so by building an HTML string and then setting innerHTML on a container than by using DOM methods like createElement/appendChild.如果您正在构建节点,在 IE 中通过构建 HTML 字符串然后在容器上设置 innerHTML 比使用 createElement/appendChild 等 DOM 方法快得多。

You can try performing long running calculations in threads (see JavaScript and Threads ), although they aren't very portable.您可以尝试在线程中执行长时间运行的计算(请参阅JavaScript 和 Threads ),尽管它们不是很便携。

You may also try using some Javascript profiler to find performance bottlenecks.您也可以尝试使用一些 Javascript 分析器来查找性能瓶颈。 Firebug supports profiling javascript. Firebug支持分析 javascript。

You could try shortening the code by您可以尝试通过以下方式缩短代码

 $(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));

or for "for" loops try或 for "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)
}

I had the same problem and my customers was reporting this as "Kill page" error.我遇到了同样的问题,我的客户将此报告为“Kill page”错误。 But now I juz got a best solution for that.但现在我得到了一个最好的解决方案。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM