不特定数のタスクをjQuery.Deferredで扱うTips
JavaScriptで非同期処理をかくとコールバック地獄になりやすい。
そんな非同期処理を可読性高く扱えるjQuery.Deferred。
しかし、1個だったり10個だったり不特定数の非同期タスクを
まとめてjQuery.Deferredで扱うのにハマったのでメモ。(順次ケースと並列ケース)
今回は例としてsetTimeout使っていますがajax処理やファイル読込みでの利用に便利だと思います。
不特定数の非同期を順次行う
非同期タスク
->A実行
-> A完了
-> B実行
-> B完了
-> C実行
-> C完了
-> 全部終わったら処理
ということがしたい場合の例です。
// タイマー function delay(data){ // 関数を返す return function(){ var ret = new $.Deferred(); console.log('start: ' + data + ' / ' + new Date().getTime()); setTimeout(function(){ console.log('end: ' + data + ' / ' + new Date().getTime()); // OK通知 ret.resolve(); }, 3000); return ret.promise(); } } // 実際の処理 (function(){ var data = [1, 2, 3]; var deferred = (new $.Deferred()).resolve(); // タスクをつめる for(var i = 0; i < data.length; i++){ deferred = deferred.then(delay(data[i])); } deferred.then(function(){ // 全部終わったらログ出す console.log('tasks finish.' + new Date().getTime()); }); })();
- ポイントは非同期処理を順次行うために関数でくるむこと(上の例ではdelay())
- for()文でdeferred.then()に順次つめていく
不特定数の並列処理を行う
非同期タスク
-> A実行
-> A完了
-> B実行
-> B完了
-> C実行
-> C完了
-> 全部終わったら処理
ということがしたい場合の例です。
// タイマー function delay(data){ var ret = new $.Deferred(); setTimeout(function(){ console.log('timeout: ' + data + ' / ' + new Date().getTime()); // OK通知 ret.resolve(); }, 3000); return ret.promise(); } // 実際の処理 (function(){ var data = [1, 2, 3]; var tasks = []; // タスクをつめる for(var i = 0; i < data.length; i++){ tasks.push(delay(data[i])); } var when = $.when.apply($, tasks); when.then(function(){ // 全部終わったらログ出す console.log('tasks finish.' + new Date().getTime()); }); })();
- ポイントは、promiseしたDeferredをタスク配列につめること
- $.when.apply($, tasks)でタスク配列を渡すこと
このようにjQuery.Deferredを使えば、複数の非同期処理を完結に表現できるのはいいですね。