Javascript - 如何避免在繁重的工作时阻塞浏览器?

新手上路,请多包涵

我的 JS 脚本中有这样一个函数:

 function heavyWork(){
   for (i=0; i<300; i++){
        doSomethingHeavy(i);
   }
}

也许“doSomethingHeavy”本身没问题,但重复它 300 次会导致浏览器窗口卡住一段不可忽略的时间。在 Chrome 中,这不是什么大问题,因为只有一个 Tab 受到影响;但对于 Firefox 来说,这是一场彻头彻尾的灾难。

有什么方法可以告诉浏览器/JS“放轻松”,而不是阻止调用 doSomethingHeavy 之间的所有内容?

原文由 Gadi A 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 275
2 个回答

您可以将调用嵌套在 setTimeout 调用中:

 for(...) {
    setTimeout(function(i) {
        return function() { doSomethingHeavy(i); }
    }(i), 0);
}

这会将对 doSomethingHeavy 的调用排队等待立即执行,但其他 JavaScript 操作可以插入它们之间。

更好的解决方案实际上是让浏览器通过 Web Workers 生成一个新的非阻塞进程,但这是特定于 HTML5 的。

编辑:

使用 setTimeout(fn, 0) 实际上需要比零毫秒长得多的时间——例如,Firefox 强制执行最少 4 毫秒的等待时间。更好的方法可能是使用 setZeroTimeout ,它更喜欢 postMessage 用于即时、可中断的函数调用,但使用 setTimeout 作为旧浏览器的后备。

原文由 apsillers 发布,翻译遵循 CC BY-SA 4.0 许可协议

您可以尝试将每个函数调用包装在 setTimeout 中,超时为 0。这会将调用推送到堆栈底部,并且应该让浏览器在每个调用之间休息。

 function heavyWork(){
   for (i=0; i<300; i++){
        setTimeout(function(){
            doSomethingHeavy(i);
        }, 0);
   }
}

编辑:我刚刚意识到这行不通。 i 每次循环迭代的值都相同,您需要关闭。

 function heavyWork(){
   for (i=0; i<300; i++){
        setTimeout((function(x){
            return function(){
                doSomethingHeavy(x);
            };
        })(i), 0);
   }
}

原文由 gen_Eric 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题