我在forloop中有一个forloop。我想知道我是否可以异步运行内部forloop而不是阻塞代码,因此它会更快。请注意,这是在vanilla javascript中完成的,而不是使用jQuery事件处理程序。
var count = 0;
for(var i = 0; i < 1000000; i++){
//HELP: run this forloop asynchonously
for(var j = 0; j < 1000000; j++){
count++;// doesn't matter when when we do the +1;
}
}
答案 0 :(得分:1)
通常,长循环不适合在Javascript中运行,即使它们是异步的。这是因为没有很好地指定线程模型(这在正在开发的新版本中正在改变) - 因此不能保证并发的语义。
Concurrent
==两件事在同一时刻执行
Asynchronous
==在开始运行的第二件事的结果出现之前,有一件事情已经完成。
这是一个重要的区别。您可以在当前浏览器中进行异步执行,但不能保证具有并发性 - 因此您的长循环很可能会干扰并阻止其他想要运行的东西,即使它是异步的。这可能是其他一些setTimeout执行线程,或渲染线程,或事件处理程序......
那么你能做些什么呢?
一个非常以Javascript为中心的事情,它是非常惯用的 - 是将任务细分为异步单元,并继续&#34;彼此你做一个工作单元,实现它的函数接收下一个工作单元,或者一个闭包回调函数在完成时通知。所以你可以这样做:
function loopProcessing(cb) {
var index = 0;
worker = function(cb) {
index += 1;
// Process expensive work unit /index/
if (index >= MAX_INDEX) setTimeout(cb,0);
setTimeout(worker,0,cb);
}
setTimeout(worker,0,cb);
}
loopProcessing(function() { alert("Finished all work!"); });
// This call returns immediately, and other threads of execution
// in the system will never have to wait more than one work unit.
当然,正如一些评论者指出的那样,这并不是制定这些工作单位的最快方式。调用函数时会有开销。但如果你的意思是&#34;慢慢&#34;实际上由于那些渲染/事件线程阻塞,前端缺乏响应能力,这样的模式会对你有所帮助。
答案 1 :(得分:1)
我对您的问题做出以下解释性假设:
真实代码中内部循环的主体需要一些时间来执行。 count++
只是为了创建MCVE而插入的替代。 (如果这个假设是假的,那么异步运行内部循环是没有意义的。增加整数计数器是几乎任何语言都可以执行的最快的操作之一。)
通过&#34;更快&#34;你的意思是这里的循环控制代码结束得更快。当然,如果它以异步方式完成,那么循环(包括内循环体)执行的整个任务将花费更长的时间。 (再次,如果这个假设是错误的,那么异步性是不合适的。)
鉴于这一切,这里有如何做到这一点:
var count = 0;
var i = 0, j = 0;
setTimeout(innerLoopBody, 0);
function innerLoopBody(){
count++; // or whatever you want the inner loop body to do
j++;
if (j >= 1000000){
j = 0;
i++;
if (i >= 1000000) return;
}
setTimeout(innerLoopBody, 0);
}
这将安排第一次&#34;循环迭代&#34;在处理完事件队列中当前所有事件后运行。每个&#34;迭代&#34;执行其工作,然后执行通常的循环条件检查,并在需要时安排下一个&#34;迭代&#34;在事件队列清空后再次运行。浏览器永远不会被阻止,并且可以处理其他事件(例如用户输入事件),但会通过执行&#34;循环来填充所有剩余时间。
答案 2 :(得分:1)
您可以定义自己的异步循环,但每个setTimeout(f, 0)
需要一些时间(通常为1 - 2 ms)。
例如,这个代码在Windows下完成大约需要1秒,在linux下大约需要2秒。
function whileAsync(cond, body, cb) {
setTimeout(function() {
if(cond()) {
body();
whileAsync(cond, body, cb);
} else cb();
}, 0);
}
function forRangeAsync(start, end, body, cb) {
whileAsync(function() {
return start < end;
},
function() {
body(start++);
}, cb);
}
var start = Date.now();
forRangeAsync(0, 1000, function(i) {
console.log(i);
}, function() {
var end = Date.now();
console.log("finished");
console.log("time = " + (end - start) + "ms");
});