【问题标题】:Avoiding "Unresponsive Script" message in a foreach loop避免在 foreach 循环中出现“无响应的脚本”消息
【发布时间】:2013-11-19 22:09:33
【问题描述】:

我正在编写一个带有非常长时间运行的 foreach 循环的 javascript 程序,如下所示:

for (property in object) {
    difficultTask();
}

我看到您可以使用setTimeout 做一些事情,这可以让您定期将控制权返回给浏览器;但是,我还没有看到任何能够使用 foreach 循环执行此操作的方法,只有带有索引的 for 循环。此外,这些任务不能异步完成,因为每次迭代都依赖于前一次迭代的结果。

我能想到的一个解决方案是将我的对象拆分为许多较小的对象并遍历它们中的每一个,在每个对象之间设置一个超时,但我想看看这是否可能不诉诸那个。

有没有办法在不彻底改变我拥有对象的方式的情况下做到这一点?

【问题讨论】:

  • 是迭代需要一段时间还是difficultTask?换句话说,您是否拥有大量的属性,或者您是否在功能上运行循环。
  • 如果您运行代码的环境支持Object.keys,您可以使用它将for...in 循环转换为for 循环并应用您之前见过的方法。跨度>
  • @zamnuts 不幸的是,两者兼而有之。
  • 你可以把你的代码放在一个 web worker 中。这里的 is "difficultTask" 到底是什么?任何计算时间长到足以在现代计算机上引起浏览器警告的东西要么是某种粒子物理实验,要么是一种损坏/错误的算法。
  • @Pointy 这是一项大型 NLP 任务

标签: javascript foreach


【解决方案1】:

将所有属性放入一个数组中,然后您可以使用索引变量和setTimeout() 循环遍历数组:

var props = [];
for (property in object) {
    props.push(property);
}

var index = 0;
function nextChunk() {
    if (index < props.length) {
        difficultTask(object[props[index++]]));

        // schedule the next chunk of work after we let the browser process events
        setTimeout(nextChunk, 1);
    }

}
nextChunk();

如果不需要 IE7 或 IE8 兼容性,您也可以将所有道具放入一个数组中:

var props = Object.keys(object);

根据长时间运行的任务的作用,网络工作者也可能是一个有趣的选择,但在 IE 10 之前不支持 IE。

【讨论】:

  • 啊,当然!我也会检查网络工作者。这主要是针对学术 CS 社区的,所以我不认为我需要很多 IE 支持...
  • @quazzieclodo - 网络工作者的限制(除了 IE 支持)是他们无法从主 JS 线程访问 DOM 或任何变量,因此他们几乎只能进行独立计算。但是,如果您的需求符合该限制,它们会很好地工作。
  • 嗯……不完全是。谢谢!
【解决方案2】:

我觉得这个sn-p可以达到你想要的效果:

function executeAndSleep(array,currentPos,step,sleepTime){
   for(var i = currentPos;i<currentPos+step&&i<array.length;i++){
      //execute your magic here
   }
   if(currentPos+step<= array.length){
       setTimeout(function(){
             executeAndSleep(array,currentPos+step,step,sleepTime);
        },sleepTime);
   }
}

你可以在这里看到它http://jsfiddle.net/victorrseloy/3utwF/

【讨论】:

    【解决方案3】:

    这听起来像是使用网络工作者的一个有用点。它们允许并发执行 javascript 代码。您可能想阅读introduction to webworkers。这篇文章很老了(现在在某些方面可能已经过时了),但仍然很好。

    浏览器支持现在是pretty good。如果您需要旧 IE 的浏览器支持,您可以使用a polyfill,这样您就可以立即开始使用 Web Worker。

    【讨论】:

    • webworkers 需要 IE 10,对于大多数至少想要支持 IE 9 的网站来说仍然难以依赖。
    • @jfriend00 有足够的 polyfills 可用,所以这不是真正的问题...
    • 那个 polyfill 只是 API 中的一个 polyfill - 它实际上并没有实现线程或分块,因此它不会解决 OP 的问题。我认为不可能有一个实现线程的polyfill。
    • @jfriend00 当然不可能以这种方式实现线程,但这不是必需的,可以只实现超时切片机制以防止 UI 冻结。我只是指能够编写在所有浏览器中工作的一致代码同时仍然获得好处的可能性。
    • 但是,如果你必须用时间片将你的工作分解成块,那么就不需要 web workers 的 polyfill。我只是不明白非线程 polyfill 如何以任何方式帮助 OP。该 polyfill 仅适用于可以改善 webworker 体验的脚本,但不需要在 webworker 中。 OP 的代码需要时间切片或在实际的 webworker 中,它不能使用假的 webworker polyfill。
    猜你喜欢
    • 1970-01-01
    • 2017-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-14
    相关资源
    最近更新 更多