2011-11-13 30 views
2

私は非同期にプログラミングするのが初めてです。私はループ内で8つのデータベースルックアップを実行する必要がある状況に遭遇しました。私はこれを達成する方法がわかりません。私のデータベースライブラリはコールバック関数でデータを返します。私は8行すべてを持てるまで私のコードを続けることができないので、8回のルックアップがすべて完了するまで中止する必要があります。コードを深くネストすることなく、多くの非同期データベース要求を実行できますか?

これは私が今想像するものの一種である:

db.world.Queue.find(@user.kingdom.troops_queue).on 'success', (troops_queue) -> 
    db.world.Queue.find(@user.kingdom.tanks_queue).on 'success', (tanks_queue) -> 
     #etc etc 

これは恐ろしいと当然の総額ですが、私は自分のコードを許可するループにそれをロールアップする方法を考えることはできません一時停止し、最後の項目がいっぱいになったときのみ続行します。私はjQueryの.each()関数のようなものを探していましたが、その関数の動作は何ですか?それがすぐに続くか、ループが終了するのを待つか?

答えて

9

よく使用される2つの方法があります。一つ目はcaolans asyncのようなライブラリを使用している:

async.parallel 
    a: (cb) -> doTaskA cb 
    b: (cb) -> doTaskB cb 
, (err, {a, b}) -> 
    # you can use err, a and b here now 

第二のアプローチはstreamlinejsです:

troops_queue = db.world.Queue.find(@user.kingdom.troops_queue).on 'success', _ 
tanks_queue = db.world.Queue.find(@user.kingdom.tanks_queue).on 'success', _ 
# go on here 

しかし、両方のソリューションは、コールバックの第一引数がエラーであると仮定 - 「それはにISN場合そうすれば、あなたはそれを変更するために使用しているライブラリの作者にバグを起こすべきです。

+0

オプション3:手動参照カウント。 – Raynos

+0

@Raynos:はい、あなたもそうすることができます... – thejh

+3

+1の 'async'。 'async'には' parallel'以外の多くの関数があります: 'waterfall'、' forEach'などです。非同期コードを書いていると非常に役に立ちます。 –

1

使用フロー制御after.js

var data = {}; 
    cb = after(8, function () { 
     // handle all 8 results 
    }), 
    queue = db.world.Queue, 
    kingdom = this.user.kingdom; 

queue.find(kingdom.troops_queue).on('success', function (result) { 
    data["troops_queue"] = result; 
    cb(); 
}); 

// etc 

P.S.のような私はそのあなたのためにcoffeescriptを修正しました。あなたがチェックできる "coffescript" いくつかのリンクのタグが付いているので

+0

(ココは*ずっと*クーラーですが)ちょっと、CoffeeScriptのは – thejh

+0

@thejhの流線は醜いだと私はココが醜悪であると推定クールです。 – Raynos

+0

Cocoはcoffeescriptよりも一貫性があり、よりクーラーな構文が追加されています。 – thejh

0

(長いスレッドを!): issue241issue287issue350issue1710(そしておそらくいくつかの...もっと)一言で言えば

  • ユーザーがthis forkを作成しましたが、それ以上管理されません。
  • Tamejsまたはstreamlinejsは現在のところ良い選択肢と考えられています。
+1

tamejsは敬意を表した選択肢と考えられています。流量制御機構がより適している。 – Raynos

+0

Tamejsは追加の構文を使用するため、コーヒーでは使用できません。 Streamlinejsが良いです。 – thejh

+0

@レイノス:IMHOのtamejsは問題への有効なアプローチです、フロー制御のメカニズムは別のアプローチです、それはより良いという事実ですか?参照を貼り付けることはできますか? Thejh:きれいではありませんが使えます:https://github.com/maxtaco/tamejs/wiki/Using-tamejs-with-CoffeeScript – tokland

1

「成功した進行」シーケンスでクエリを整理できます。このシーケンスは、JavaScriptでちょっとこのように、継続スタイルのループで使用することができます。

var lookups = [ 
    function(){ Q.find(@user.kingdom.troops_queue; }, 
    function(troops_queue){ Q.find(...tanks_queue; }, 
    function(tanks_queue){ Q.find(...next_queu; }, 
    .... 
]; 

そして、この「層状」配列は

function proceedOn(sequence, previous_result) {  
    var first = sequence[0]; 
    first(previous_result).onSuccess(function(result){ 
    proceedOn(sequence[1..], result); 
    }); 
} 

proceedOn(lookups); 
私が撮った

(のような非同期ミルをdrewnすることができます

+0

'lookups'は配列かオブジェクトですか?見えない – thejh

+0

@thejh:確かに:それは配列です。 – xtofl

1

私はいつも自分のプロジェクトにStepを使っています。とても清潔でいいです。ここで

は、行のいくつかのコールバックの例です:

Step(
    function readSelf() { 
    fs.readFile(__filename, this); 
    }, 
    function capitalize(err, text) { 
    if (err) throw err; 
    return text.toUpperCase(); 
    }, 
    function showIt(err, newText) { 
    if (err) throw err; 
    console.log(newText); 
    } 
); 

あなたはまた、(this.parallel幸いにも、いくつかの並列ものを行うだけにして、コールバックをトリガすることもできます)そのためだけのものです:

Step(
    // Loads two files in parallel 
    function loadStuff() { 
    fs.readFile(__filename, this.parallel()); 
    fs.readFile("/etc/passwd", this.parallel()); 
    }, 
    // Show the result when done 
    function showStuff(err, code, users) { 
    if (err) throw err; 
    console.log(code); 
    console.log(users); 
    } 
) 
関連する問題