如何在Javascript中执行不会阻塞UI的循环?

Gud*_*ain 3 javascript

我的页面上有一些JavaScript,执行时间很长(介于10到30秒之间)

代码基本上是这样的:

//Iterate over all the elements in the array
for(int i=0; i<array.length; i++){
   //Complex stuff for each element
}
Run Code Online (Sandbox Code Playgroud)

问题在于,在执行此代码时,UI没有响应。

有什么办法解决这个问题?我知道javascript具有某种异步性,但是我以前从未真正使用过它。

同样,元素的处理顺序必须始终是它们在数组中出现的顺序。

编辑:我用setTimeout()和“重复”尝试了下面的解决方案,但是它仍然不能解决我的问题。我想这是因为数组的大小不是很大,但是每个元素的计算量都很大。

另外,我想响应的UI是一个动画加载gif。由于每个项目的计算量太大,因此动画是草率的。

Que*_*tin 5

创建一个变量并将其设置为计数器的起始值。

创建一个函数,该函数:

  1. 做循环主体做什么
  2. 增加计数器
  3. 测试以查看计数器是否仍在长度以下,如果是,则再次调用该函数

此时,您将拥有与已经拥有的功能相同的功能。

要在每次调用函数之间暂停并留出时间触发其他函数,请将对函数的直接调用替换为对的调用,setTimeout并将该函数用作第一个参数。

var counter = 0;
function iterator () {
    //Complex stuff for each element
    counter++;
    if (counter < array.length) {
        setTimeout(iterator, 5);
    } 
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*don 5

JavaScript 使用称为“事件循环”的东西。基本上,有一个线程在每个事件发生时执行该代码。

有一个名为的函数setTimeout,您可以使用它来使您的 Javascript 代码在循环的未来迭代中运行。一些开发人员在长时间运行的 Javascript 任务期间用来保持 UI 响应的一个技巧是定期调用要在超时为零的情况下运行的代码。这会导致代码几乎立即执行,而不会锁定事件循环。

例如,你可以写

var i = 0;
setTimeout(myFunction, 0);

function myFunction() {
    // complex stuff for each element.
    i++;
    if (i < array.length)
        setTimeout(myFunction, 0);
}
Run Code Online (Sandbox Code Playgroud)

请注意,在现代浏览器上,只要 Javascript 代码正在执行,UI 就会无响应。有些浏览器甚至会弹出一条消息,敦促用户杀死该脚本;很坏!

此外,在现代浏览器中,有一个称为“Web Workers”的新功能。Web Workers 允许 Javascript 代码在单独的线程中执行。您可以根据需要创建任意数量的线程,因此如果您的任务很容易并行化,也可以考虑使用 Web Worker。