以下是promise的簡單實現
var Deferred = function () {
this.promise = new Promise();
};
var Promise = function () {
this.queue = [];
this.isPromise = true; //判斷是否返回了一個promise對象
}
Promise.prototype.then = function (fulfilledHandler,errorHandler,progressHandler) {
var handler = {};
if(typeof fulfilledHandler === 'function'){
handler.fulfilled = fulfilledHandler;
}
if(typeof errorHandler === 'function'){
handler.error = errorHandler;
}
this.queue.push(handler);
return this;
}
//生成回調函數
Deferred.prototype.callback = function () {
var that = this;
return function (err,file) {
if(err){
return that.reject(err);
}
that.resolve(file);
}
}
Deferred.prototype.resolve = function (obj) {
var promise = this.promise;
var handler;
while(handler = promise.queue.shift()){
if(handler && handler.fulfilled){
var ret = handler.fulfilled(obj);
if(ret &&ret.isPromise){
ret.queue = promise.queue;
this.promise = ret;
return ret;
}
}
}
}
Deferred.prototype.reject = function (err) {
var promise = this.promise,handler;
while(handler = promise.queue.shift()){
if(handler && handler.error){
var ret = handler.error(err);
if(ret && ret.isPromise){
ret.queue = promise.queue;
this.promise = ret;
return ;
}
}
}
}
這裏我們以兩次文件讀取爲例子,以驗證該設計的可行性。這裏假設讀取第二個文件是依賴於第一個文件中的內容的,相關代碼如下:
var readFile1 = function (file,encoding) {
var deferred = new Deferred();
fs.readFile(file,encoding,deferred.callback());
return deferred.promise;
}
var readFile2 = function (file,encoding) {
var deferred = new Deferred();
fs.readFile(file,encoding,deferred.callback());
return deferred.promise;
}
readFile1('file1.txt','utf8').then(function (file1) {
return readFile2(file1.trim(),'utf8');
}).then(function (file2) {
console.log(file2);
});
要讓Promise支持鏈式執行,主要通過以下兩個步驟
(1)將所有的回調都存放在隊列中
(2)Promise完成時,逐個執行回調,一旦檢測到返回了新的Promise對象,停止執行,然後將當前
deferred對象的Promise引用改變爲新的Promise對象,並將隊列中餘下的回調轉交給它。
這裏的代碼主要用於研究Promise的執行原理,在更多細節的優化方面,Q或者when等Promise庫做得更好,實際應用時請採用這些成熟庫。
注意:Promise.prototype.then
的函數實現中return this;
才實現了鏈式調用,this指代的是當前promise實例。