在另一个异步循环内的Javascript异步循环

问题描述:

我在jQuery中使用each()在div中迭代子代时有一些代码。 里面的每个文本都被分割成单词。每个单词都用'for'循环处理。 此功能可能需要很长时间,并可以冻结浏览器,所以...在另一个异步循环内的Javascript异步循环

有没有办法在另一个异步循环内创建异步循环,但有人正在等待其他人完成?

有人能告诉我正确的方向吗?

我想出了这样的事情:

var queue = []; 
var nlevel = 0; 

function work() { 
    nlevel = queue.length-1; 

    var arr = queue[nlevel][0]; 
    var process = queue[nlevel][1]; 
    var cnt = queue[nlevel][2]; 
    var item = arr[cnt]; 

    process.apply(item); 

    cnt++; 
    queue[nlevel][2] = cnt; 

    if (cnt < arr.length) { 
     setTimeout(work, 1); 
    } else { 
     if (queue.length>1) { 
      queue.pop(); 
      setTimeout(work, 1); 
     } 
    } 
} 

function each(arr, process) { 
    queue.push([arr, process, 0]); 

    setTimeout(work, 1); 
} 


each(['one', 'two', 'three'], function() { 
    alert(this); 

    each([1, 2, 3, 4], function() { 
     alert(this); 
    }); 
}); 

,但它有一些重大的错误,我不能修复它。

+4

我确定有一个解决方案,但是如果没有看到实际的代码和更多关于您想要更改的代码的具体描述,我们无法真正帮助您。 – jfriend00 2012-02-06 23:19:20

一种方法是创建工作项队列中处理:

var queue = []; 

广场项目在此队列中,而不是加工处理的时候了:

queue.push(item); 

然后启动一个定时器循环处理项目:

var delayBetweenItems = 10; 
var processItemFromQueue = function() { 
    if (queue.length) { 
     item = queue.shift(); 
     doStuff(item); 
     setTimeout(delayBetweenItems, processItemFromQueue); 
    } 
}; 
setTimeout(processItemFromQueue, delayBetweenItems); 
+0

Jacob不应该将'setTimeout'函数的参数颠倒过来,以便函数先传递,然后延迟?然后它会读为'setTimeout(processItemFromQueue,delayBetweenItems);'。参考[MDN setTimeout()](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers.setTimeout) – Ash 2014-12-24 00:16:22

+0

是的,感谢您的更正,@Ash。定影。 – Jacob 2014-12-25 20:51:56

您可以使用Web Workers在后台线程中运行多个脚本。但是它们在每个浏览器中都不被支持。看到Mozilla的这篇文章或者简单问谷歌:https://developer.mozilla.org/En/Using_web_workers

您可以使用SetTimeout(0,...)定期向“产量”控制浏览器,以防止冻结浏览器(但不会执行任何快,事实上它可能会稍微慢一点)。

查看this answer作为技术的一个例子,我不能没有看到你的代码更具体。你可以这样做

假设你当前的代码是舒美特兴与此类似:

function processWord(word, i, j) { 
    // do something with the current word, where 
    // (if it's needed) i is the index into the elements 
    // and j is the index into the current element's words 
} 

$("#divId").children().each(function(i) { 
    var words = $(this).text().split(" "), 
     j; 
    for(j = 0; j < words.length; j++) { 
     processWord(words[j], i, j); 
    } 
}); 

可以重写,这样做既外(i)和内部(J)与setTimeout()循环:

// assumes the same processWord() function as above 

(function(){ 
    var $items = $("#divId").children(), 
     words, 
     i, j, 
     iMax, jMax; 

    function doIteration() { 
     if (j === jMax) { 
      if (++i === iMax) 
      return; 

      // outer loop processing 
      words = $($items[i]).text().split(" "); 
      jMax = words.length; 
      j = 0; 
     } 
     if (j < jMax) { 
      // inner loop processing 
      processWord(words[j], i, j); 
      j++; 
     } 

     setTimeout(doIteration, 1); 
    } 

    iMax = $items.length; 
    i = j = jMax = -1; 
    doIteration(); 
})(); 

工作演示:http://jsfiddle.net/sp8Wr/

doIteration()函数通过适当地处理一些计数器并通过setTimeout()调用自己来执行下一次迭代来模拟嵌套循环。包装整个事物的立即执行匿名函数对于这个过程并不重要,它仅仅是为了限制变量的范围。

是的,这可能可以做得更好,但这正是我动态提出的 - 显然你会根据自己的处理情况修改它。

(如果你不关心什么顺序的话得到,只要processWord()功能得到处理的每个单词这可以很容易地进行整洁相关的ij正确的价值观,但我不”没有时间做一个整洁的版本,按顺序处理。)