有没有办法使代码块本身非阻塞

在使用节点之后,我不得不习惯以非阻塞的方式编写我的代码,但是我能做到这一点的主要方法是使用本身是asynchronous的函数。 例如: stat(f,callback)或者forEach(array, callback)他们会自动把你所给出的callback从我认为是主执行高速公路的地方送回来,并在被调用后立即返回。

我想知道的是: 我怎样才能告诉ECMA引擎asynchronous执行一个函数?nomatter是什么?

我的特殊用例涉及遍历一个DOM childList的for循环来parsing数千个元素; 我的问题是,每个其他元素是一个文本节点,我想跳过。 虽然我会使用forEach()这不是最好的,我只看到for(a,i=0;a=table[i];i=i+2){/*process 'a'*/}是能够纠正那是以阻塞为代价的。 最好的行动是什么?

奖金问题: NodeJS的编码实践在JS需要做繁重工作的用例中,在客户端应用程序中是否有任何理由?

注意: Array.prototype.forEach是同步的,而不是asynchronous的。 任何在JS标准( ECMAScript 5th edition )中定义的东西都不能是asynchronous的,因为标准没有定义asynchronous语义(Node.js和DOM)。

您可以使用setTimeout (适用于浏览器和Node.js)或process.nextTick (Node.js特定):

 for (...) { doWorkAsync(...); } function doWorkAsync(...) { setTimeout(doWorkSync.bind(null, ...), 0); } function doWorkSync(...) { ... } 

如果您select利用闭包,请谨慎使用自由variables,因为最终调用callback时,variables可能会发生变化。

使用asynchronous框架(例如kriskowal的Q (可通过Node.js和现代浏览器移植)),您可以执行mapreduce风格的编程:

 var Q = require('q'); // npm package 'q' function getWorkloads() { var workloads = [ ]; for (...) { workloads.push(Q.fcall(doWorkSync.bind(null, ...))); } return workloads; } Q.all(getWorkloads()).then(function (results) { // results array corresponds to // the array returned by getWorkloads. }); 

我在同一条船上 我有点喜欢Node的asynchronous函数,所以我写了这个async For和ForEach函数。 它使用“setTimeout(Func,0);” 招。

这是图书馆:

  var WilkesAsyncBurn = function() { var Now = function() {return (new Date());}; var CreateFutureDate = function(milliseconds) { var t = Now(); t.setTime(t.getTime() + milliseconds); return t; }; var For = function(start, end, eachCallback, finalCallback, msBurnTime) { var i = start; var Each = function() { if(i==-1) {return;} //always does one last each with nothing to do setTimeout(Each,0); var burnTimeout = CreateFutureDate(msBurnTime); while(Now() < burnTimeout) { if(i>=end) {i=-1; finalCallback(); return;} eachCallback(i); i++; } }; Each(); }; var ForEach = function(array, eachCallback, finalCallback, msBurnTime) { var i = 0; var len = array.length; var Each = function() { if(i==-1) {return;} setTimeout(Each,0); var burnTimeout = CreateFutureDate(msBurnTime); while(Now() < burnTimeout) { if(i>=len) {i=-1; finalCallback(array); return;} eachCallback(i, array[i]); i++; } }; Each(); }; var pub = {}; pub.For = For; //eachCallback(index); finalCallback(); pub.ForEach = ForEach; //eachCallback(index,value); finalCallback(array); WilkesAsyncBurn = pub; }; 

用法示例:

  WilkesAsyncBurn(); // Init the library console.log("start"); var FuncEach = function(index) { if(index%10000==0) { console.log("index=" + index); } }; var FuncFinal = function() { console.log("done"); }; WilkesAsyncBurn.For(0,2000000,FuncEach,FuncFinal,50); 

打印:索引= 10000索引= 20000索引= 30000等“完成”

更多的研究如果感兴趣

setTimeout和setInterval的最小开销时间约为2到10毫秒,因此,释放数千甚至数百万计时器的速度将会很慢。 所以基本上,如果你需要在不locking浏览器的情况下执行数千或更多的循环,你需要更像是一个线程(gasp),并且将某些代码“烧”一段时间,而不是设置迭代次数。