1

すべてのデータをサーバーに保存するJavaScriptアプリがあり、REST APIを使用してサーバーとクライアントを通信します。

非同期呼び出しを非表示にするネストされた非同期呼び出しまたはネストされた同期呼び出しがますます増えるまで、それらは正常に機能します。例えば:

function asyncFoo(callback) {
  callback();
}

function syncCallHidingAsyncCall(){
  syncStuff();
  asyncFoo(function(){
    syncFoo()
  });
}

function nestedAsyncCall(callback){
  asyncFoo(function(){
    anotherAsyncCall(callback);
  })
}
// this make refactor code become so hard.
// if we want add step2() after nestedAsyncCall();
// instead of add one line of code
// we need first add callback param in every asyncCall, then pass step2 as a callback

そして、いくつかの不要な非同期呼び出し:

// we actually only verify this once.
function isLogin(callback){
  if (!App._user) {
    ServerApi.getCurUser(function(data){
      App._user = data.user;
      callback(App._user)
    });
  }
  callback(App._user)
}

function syncCallNeedVerfifyLogin(callback){
  // user only need login once, so in most case this is really only a sync call.
  // but now I have to involve a unnecessary callback to get the return value
  isLogin(function(){
    callback(syncStuff())
  })
}

プロジェクトがどんどん大きくなっていくと、どちらが待つ必要があり、どちらが魔法をかけてくれるのか、私たちは彼らの関係を忘れ始めます。そして、いくつかの非常に小さなことをサーバーで検証する必要があるという理由だけで、ますます多くの機能が非同期になります。

だから私は、このプロジェクトの設計上の問題に違いないと感じ始めました。私はベスト プラクティスまたはデザイン パターンを探しています。または、この種の重い通信アプリでいくつかのルールに従う必要があります。

手伝ってくれてありがとう。

4

3 に答える 3

0

Bergi がコメントで述べているように、探しているパターンは deferred / promises と呼ばれます。jQueryに組み込まれた実装があります。ドキュメントから:

jQuery.Deferred() メソッドを呼び出して作成された連鎖可能なユーティリティ オブジェクト。複数のコールバックをコールバック キューに登録し、コールバック キューを呼び出し、同期関数または非同期関数の成功または失敗の状態を中継できます。

他にもさまざまな実装があり、そのうちのいくつかはこのスタックオーバーフローの質問で概説されています。

于 2013-04-22T23:36:29.283 に答える
0

次のようなキューシステムを作成します。

function Queue() {
    this.queue = [];
}
Queue.prototype.i = -1;
Queue.prototype.add = function(fn) {
    if (typeof fn !== "function")
        throw new TypeError("Invalid argument");

    this.queue.push(fn);
}
Queue.prototype.next = function() {
    this.i++;
    if (this.i < this.queue.length) {
        this.queue[this.i].appy(this, arguments);
    }
}
Queue.prototype.start = function() {
    if (this.i !== -1)
        throw new Error("Already running")
    this.next.apply(this, arguments);
}

そして、次のように使用します。

var q = new Queue();

q.add(function() {
    // do something async
    // In the callback, call `this.next()`, passing
    //    any relevant arguments
})
q.add(function() {
    // do something async
    // In the callback, call `this.next()`, passing
    //    any relevant arguments
})
q.add(function() {
    // do something async
    // In the callback, call `this.next()`, passing
    //    any relevant arguments
})

q.start();

デモ: http://jsfiddle.net/4n3kH/

于 2013-04-22T23:46:06.717 に答える