当前位置: 动力学知识库 > 问答 > 编程问答 >

How to run a function inside a forloop asynchronously in javascript

问题描述:

I have a forloop within a forloop. I'm wondering if I can make the inner forloop run asynchronously instead of blocked code so it'll be faster. Note that this is to be done in vanilla javascript and not using jQuery event handlers.

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;

}

}

网友答案:

In general long loops are not great for running in Javascript, even if they are asynchronous. This is because the threading model is not well specified (this is changing however in the new version being developed) - and consequently there are no guarantees about the semantics of concurrency.

Concurrent == Two things execute at the same instant in time

Asynchronous == One thing finishes before the result from a second thing it started running is available.

It's an important distinction. You can have asynchronous execution in current browsers, but there is no guarantee to have concurrency - so your long loop is very likely going to interfere with and block something else that wants to run, even if it's async. That might be some other setTimeout thread of execution, or a render thread, or an event handler...

So what can you do about this?

A very Javascript-centric thing to do, it's very idiomatic - is to subdivide tasks up into asynchronous units that "continue" from one another. You do a unit of work, and the function that implements it receives the next unit of work, or a closure callback to notify when it is finished. So you might do something like:

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.

Of course, this isn't the fastest way to crank out those work units - as some commenters pointed out. There is overhead when calling functions. But if what you mean by "slowness" is actually lack of responsiveness in the front-end due to those render / event threads blocking, patterns like this will help you.

网友答案:

I'm making the following interpretive assumptions about your question:

  • The body of the inner loop in your real code takes some time to execute. count++ is just a stand-in you inserted for the sake of creating an MCVE. (If this assumption is false, then it makes no sense to run the inner loop asynchronously. Incrementing an integer counter is one of the fastest operations you can perform in almost any language.)

  • By "faster" you mean the loop control code here ends faster. Of course the entire task performed by the loops (including the inner loop body) will take much longer if it's done asynchronously. (So again, if this assumption is false, then asynchronicity is inappropriate.)

Given all that, here's how to do it:

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);
}

This schedules the first "loop iteration" to run once all events currently in the event queue are done being handled. Each "iteration" performs its work, then performs the usual loop condition checks, and if needed schedules the next "iteration" to run, again when the event queue has been emptied. The browser is never blocked, and can handle other events (such as user input events), but will fill all remaining time with execution of your "loop".

网友答案:

You can define yourself asynchronous loops but each setTimeout(f, 0) will take some time (usually 1 - 2 ms). For example, this code will take about 1s to finish under windows and nearly 2s under linux.

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");
  });
分享给朋友:
您可能感兴趣的文章:
随机阅读: