大規模なリファクタリングを行いました。これは、進行状況を監視する最後の実用的な例です。
今重要な部分。
- 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)