首先回顧一下jQuery的deferred對象:
jQuery的deferred對象
關於Promise的進化史
在jQuery1.4中,還沒有promise這個概念,寫一個ajax,就得寫回調函數,就像這樣:
$.get('/myData', {
success: onSuccess,
failure: onFailure,
always: onAlways
})
到了jQuery1.5+之後,有了promise,就可以給ajax 的get返回的就是一個promise對象(我這樣理解不知道對不對)
然後代碼的形式就變成了這樣:
var promise = $.get('/myData');
promise.done(onSuccess);
promise.fail(onFailure);
promise.always(onAlways);
這樣的好處是Promise對象和EventEmitter對象一樣,可以向同一事件綁定任意多的處理器。
promise就是deferred
或者說是用deferred就可以生成一個promise對象
var prompt = new $.Deferred();
$('#playGame').focus().on('keypress', function(e) {
var Y = 121,
N = 110;
if (e.keyCode === Y) {
prompt.resolve();
} else if (e.keyCode === N) {
prompt.reject();
} else {
return false; // they must choose!
}
});
prompt.done(function() {
console.log('Starting game...');
});
prompt.fail(function() {
console.log('No game today.');
});
prompt.always(function() {
console.log('A choice was made');
});
輸入y就會打印
輸入n就會打印
即,每次調用promtDeferred對象,都會先運行一下always(),再運行done或者fail(調用promt.resolve()就是done,reject就是fail)
同時測試結果顯示錶明,調用了一次之後就不管用了。也就是說Promise對象只能執行或拒絕一次,之後就失效了。期間Promise對象會一直保持掛起狀態。
這裏我們可以調用promt.state()方法,確實是“pending”
這裏我打印一下promt對象的屬性和方法,就可以看到promise的方法有always,done,fail,notify…..
生成一個純promise對象
上面的圖,我們可以看到promt有一個promise()方法,沒錯,就是調用這個方法來生成純promise對象。
promise對象和Deferred對象的區別是,沒有resolve和reject方法。promise的promise也是指向自己。
因此可以考慮這是一個封裝:每個deferred對象都含有一個promise對象,每個promise對象都代表着一個deferred對象。有了deferred對象,就可以控制其狀態,有了promise對象就可以讀取其狀態。
jQuery中的Promise對象
還是參見上面的圖,很多方法都沒有介紹
首先,說明的是在jQuery中,不僅只有Ajax函數(.ajax,.get, .post)可以返回Promise對象,動畫函數也可以返回Promise對象。
notify和progress
Promise對象接受3種回調方式:done、fail和progress。
- 執行Promise對象時,運行的是done回調;
- 拒絕Promise對象時,運行的是fail回調;
- 對於掛起狀態的Deferred對象調用notify,運行的是progress回調;
when
when相當於Promise執行情況的邏輯與運算符(AND)。一旦給定的所有Promise均已執行,就立即執行when產生的Promise對象;
或者,一旦給定的任意一個Promise被拒絕,就立即拒絕when產生的Promise。
pipe
pipe是jquery1.6+提供的方法。
pipe是promise上的方法,pipe對象也是promise對象。
初始Promise對象的行爲一直級聯到管道末尾的promise對象。
Promise對象的使用
用Promise對象代替回調函數
deferreCallback = function(deferred) {
return function(err) {
deferred.reject(err)
} else {
deferred.resolve(Array.prototype.slice.call(arguments, 1));
}
}
var fileReading = new $.Deferred();
fs.readFile(filename, 'utf8', deferreCallback(fileReading));
文件讀取是一個耗時的工作,我們將Priomise對象代替回調函數,當文件讀取成功就執行deferred.resolve,失敗就執行deferred.reject。