Blackbing Playground

[javascript] 利用 Deferred 處理動態的順序性任務

前情提要

之前寫了一篇 利用 Deferred 處理順序性任務,主要是利用 Deferred 來避免 callback 寫法的缺點。

不過在實務上,可能會遇到更複雜一點的情況,例如:

pipe array flow.png

這張圖的意思是要確保任務是 A->B->C 的執行順序,而且當 A,B,C 有任一個 fail 就會停止,不會再執行下去。我們直接來看應該要怎麼處理這樣的程式。

範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var a = $.Deferred();
var b = $.Deferred();
var c = $.Deferred();
var checkA = function() {
console.log('checkA');
return a.reject();
};
var checkB = function() {
console.log('checkB');
return b.resolve();
};
var checkC = function() {
console.log('checkC');
return c.reject();
};
var checkAll = function(){
var _dfr = $.Deferred().resolve();
_dfr = _dfr
.pipe(checkA)
.pipe(checkB)
.pipe(checkC);
return _dfr.promise();
};
checkAll().done(function() {
return console.log('checkAll done');
}).fail(function() {
return console.log('checkAll fail');
});

為了簡化程式,我直接在 checkA/B/C 的 function 中回傳 Deferred reject or resolve。上述的例子可以直接看結果
可以看到結果只會印出

1
2
"checkA"
"checkAll fail"

是因為 checkA 執行時就被 reject 了,因此不會再繼續執行下去。您可以自己試試看將 reject 改成 resolve 看一下執行的結果會變成怎麼樣。

Dynamic task function

實務操作上 task 也許會是動態的,我們可以很簡單的將任務指派成一個 array 的形式,例如:

1
var funList = [checkA, checkB, checkC];

然後將 checkAll 的任務串起來

1
2
3
4
5
6
7
8
var checkAll = function(){
var _dfr = $.Deferred().resolve();
var funList = [checkA, checkB, checkC];
for(var i=0; i<funList.length; i++){
_dfr = _dfr.pipe(funList[i]);
}
return _dfr.promise();
};

最後的程式碼結果請猛擊這裡

結論

要注意的是不能用 jQuery.when,when 是一次發出去執行,會等到全部做完才會回來。

Reference