6

この質問は、 jQuery Deferred として実行される非非同期関数の慎重に抽出されたバージョンです。

2 つの jsfiddles があります。

  1. http://jsfiddle.net/XSDVX/1/ - ここでは、notify() 関数を呼び出しても、progress イベントは発生しません。

  2. http://jsfiddle.net/UXSbw/1/ - ここでは進行状況イベントが期待どおりに発生します。

唯一の違いは、1 行のコードです。

setTimeout(dfd.resolve,1);

dfd.resolve();

質問は次のとおりです。

  1. .then は、解決を遅らせたときに、このコールバックが戻る前に呼び出された .notify をどのようにキャッチしますか? 考えてみてください。.then は、最初のパラメーターから返された遅延オブジェクトを受け取り、そこから新しい遅延オブジェクトを作成し、進行状況イベントと失敗イベントにバインドします。遅延が返される前に通知が呼び出された場合、.then は setTimeout を使用してもそれをどのようにキャッチしますか? (これを依頼してくれたhttps://stackoverflow.com/users/400654/kevin-bに感謝します)

  2. プログレス コールバックをなくしてもsetTimeout()、まだ進行状況のコールバックを起動できますか?

4

1 に答える 1

1

大規模なリファクタリングを行いました。これは、進行状況を監視する最後の実用的な例です。

今重要な部分。

  • JQuery の deferred は、解決が呼び出された後、進行状況のコールバックを実行しません ( 1 つの例外があります)。あなたの例(setTimeoutなし)では、遅延はすぐに解決され、進行状況を実行する機会はありません。
  • 最終的な Deferred で何かをトリガーする前に、すべてのコールバック、特に進行中のコールバックのフックを実行します。これは、トリガーを設定した後、最終的な Deferred (現在はビーコン) を実行関数に渡すことによって実現されます。
  • API をリファクタリングして、実行される func が不可知論的に延期されるようにしました。
  • このソリューションは、実行チェーンを継続するために、memo.then 関数内で (reduce イテレーター関数への) Deferred ローカルのクロージャーを使用します。

編集:最初の質問を忘れました。この動作は、クロージャ(「x」関数の dfd 変数) によって実現されます。

関数 "x" はすぐに戻ります (実行チェーンのすべての Deferred が作成され、"executePromiseQueueSync" の done、fail、progress フックがフックされているため、現在処理できる通知イベントをトリガーした後)。

また、setTimeout の関数はクロージャーで dfd を「閉じる」ため、「x」が返されても変数にアクセスできます。「then」呼び出しは、最初の遅延オブジェクトにリンクされた次の遅延オブジェクトを作成することによって続行されます。

JS VM が解放された後 (他に行うことはありません)、setTimeout は関連する関数をトリガーし、(クロージャーによって) 「閉じられた」dfd 変数にアクセスします。Deferred は解決され、チェーンは続行できます。

EDIT2:これはリファクタリングされたバージョンで、実行時間が長く、サポートされている延期された関数のサポートを追加し、呼び出し元に進行状況を通知します。

EDIT3: これは別のバージョンで、アンダースコア バインディングがなく、jq-ui プログレスバーの例があります。

ところで、これは複雑なアプリの初期化ルーチンにとって非常に良い考えです。

ソース(最初のバージョンの)

function executePromiseQueueSync(queue, beacon){
    var seed = $.Deferred(),
        le = queue.length,
        last;
    beacon.notify(0);
    last = _.reduce(queue, function(memo, ent, ind){
       var df = $.Deferred();
        df.then(function(){
            console.log("DBG proggie");
            beacon.notify((ind+1)/le*100);
        });
        console.log("DBG hook funk "+ind);
        memo.then(function(){
          console.log("DBG exec func "+ind);
          ent.funct.apply(null, ent.argmnt);
          df.resolve();
        });

        return df.promise();
    }, seed.promise());
    last.then(function(){
        beacon.resolve(100)
    });
    seed.resolve(); // trigger

    return beacon.promise();
}

function x(){
    // do stuff
    console.log("blah");
}

var promisesQueue = [],
     beacon = $.Deferred(); 

promisesQueue.push({funct: x, argmnt:[]});
promisesQueue.push({funct: x, argmnt:[]});
promisesQueue.push({funct: x, argmnt:[]});

function monTheProg(pct) 
{
    console.log('progress '+pct);
}

// first hook, then exec
beacon.then(function(){
        console.log('success');
    }, function(){
        console.log('failure');
    }, monTheProg);

// do the dance
executePromiseQueueSync(promisesQueue, beacon)
于 2013-05-11T10:39:34.763 に答える