2

ノードをたくさん使用した後、ブロックしない方法でコードを書くことに慣れなければなりませんでしたが、これを行う主な方法は、それ自体が非同期の関数を使用することです。例:stat(f,callback)またはforEach(array, callback)、メインの実行ハイウェイと思われるものから、あなたが与えたコールバックを自動的に取得し、呼び出された直後に戻ります。

私が知りたいのは、ECMAエンジンに、関数を非同期的に実行するように指示するにはどうすればよいですか?

私の特定のユースケースでは、DOMのchildListに対してforループを繰り返して、数千の要素を解析します。私の問題は、他のすべての要素がスキップしたいテキストノードであるということです。私はこれを使用するのが最善ではありませんでしたが、ブロックすることを犠牲にして、それを修正できることforEach()しかわかりません。for(a,i=0;a=table[i];i=i+2){/*process 'a'*/}最善の行動方針は何でしょうか?

ボーナスの質問: NodeJSのコーディング手法は、JSが手間のかかる作業を行わなければならないユースケースで、クライアントサイドアプリケーションに何らかの根拠をもたらしますか?

4

2 に答える 2

3

注:Array.prototype.forEach非同期ではなく同期です。JS標準(ECMAScript 5th edition)で定義されているものはすべて非同期にすることはできません。これは、標準が非同期セマンティクスを定義していないためです(Node.jsとDOMは定義しています)。

setTimeout(ブラウザおよびNode.jsで動作)またはprocess.nextTick(Node.js固有)を使用できます。

for (...) {
    doWorkAsync(...);
}

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

function doWorkSync(...) {
    ...
}

クロージャを利用する場合は、コールバックが最終的に呼び出されたときに変数が変更される可能性があるため、自由変数を使用する場合は注意してください。

Q by kriskowal (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.
});
于 2012-05-27T17:47:07.873 に答える
0

私は同じ船に乗っています。私はNodeの非同期関数が好きだったので、この非同期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ミリ秒であるため、数千または数百万のタイマーの起動が理由もなく遅くなります。したがって、基本的に、ブラウザをロックせずに数千以上のループを実行する必要がある場合は、スレッド(gasp)のようになり、一定の反復回数ではなく、一定の時間コードを「書き込む」必要があります。

于 2013-03-29T20:32:35.713 に答える