Promise對象是一個代理對象(代理一個值)雁刷,被代理的值在Promise對象創(chuàng)建時可能是未知的。它允許你為異步操作的成功和失敗分別綁定相應的處理方法(handlers)保礼。這讓異步方法可以像同步方法那樣返回值沛励,但并不是立即返回最終執(zhí)行結果,而是一個能代表未來出現的結果的promise對象炮障。
一個Promise有以下幾種狀態(tài):
- pending: 初始狀態(tài)目派,成功或失敗狀態(tài)。
- fulfilled: 意味著操作成功完成胁赢。
- rejected: 意味著操作失敗企蹭。
Promise的一般使用方式如下:
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('Resolved!');
}, 500);
});
p.then(function(msg) {
console.log('Promise has been ' + msg);
}).catch(function(err) {
console.log('Promise has an error!');
});
注:如果你不是很了解Promise及其使用,可以查看一下官方文檔Promise
根據這種鏈式調用方式智末,我們可以推測一下Promise內部大概是什么結構:
- 有一個變量练对,用于記錄當前Promise對象的狀態(tài)
- 有一個變量,用于存儲當前Promise對象的數據
- 有一個數組吹害,用于存儲成功時的回調
- 有一個數組,用于存儲失敗時的回調
- 有一個then方法虚青,用于傳入resolve和reject方法來消費Promise
- 有一個catch方法它呀,用于捕獲異常
所以目前為止,Promise的內部構造大致為:
function Promise(executor) {
var self = this;
self.status = 'pending';
self.data = undefined;
self.onReslovedCallback = [];
self.onRejectedCallback = [];
}
Promise.prototype.then = function(onResolved, onRejected) { // todo }
Promise.prototype.catch = function(onRejected) { // todo }
回到之前的調用舉例中棒厘,我們看到傳入的函數中有兩個參數纵穿,一個為resolve,另一個reject奢人,以我們的使用經驗可以了解到谓媒,resolve會將結果推送至下一個then中,而reject會將結果推送至下一個catch中何乎。這兩個皆為函數句惯,所以我們可以添加一些東西到Promise中:
function Promise(executor) {
var self = this;
self.status = 'pending';
self.data = undefined;
self.onReslovedCallback = [];
self.onRejectedCallback = [];
function resolve(data) { // todo }
function reject(reason) { // todo }
try {
executor(resolve, reject);
}
catch(err) {
reject(err);
}
}
resolve的作用是將Promise對象狀態(tài)置為resolved土辩,同時將數據傳遞給各個回調,然后再執(zhí)行回調方法抢野,所以我們能夠寫出這個方法:
function Promise(executor) {
// ...
function resolve(data) {
if(self.status === 'pending') {
self.status = 'resolved';
self.data = value;
for(var i=0;i<self.onReslovedCallback.length;i++) {
self.onReslovedCallback[i](value);
}
}
}
// ...
}
同理拷淘,我們能夠寫出reject方法:
function Promise(executor) {
// ...
function reject(reason) {
if(self.status === 'pending') {
self.status = 'rejected';
self.data = reason;
for(var i=0;i<self.onRejectedCallback.length;i++) {
self.onRejectedCallback[i](reason);
}
}
}
// ...
}
對于then方法,我們從調用可以看出指孤,它將消費Promise的方式傳入進來启涯。當然,Promise里存在有三種狀態(tài)恃轩,我們需要分別處理:
Promise.prototype.then = function(onResolved, onRejected) {
var self = this;
var promise2;
// 當出現promise.then().then()...這種調用時结洼,我們直接將數據進行返回,這樣可以實現穿透
onResolved = typeof onResolved === 'function' ? onResolved : function(v) {
return v;
};
// 跟上面一樣叉跛,為了實現穿透松忍,直接將數據進行返回
onRejected = typeof onRejected === 'function' ? onRejected : function(r) {
return r;
};
// 當Promise對象狀態(tài)為resolved時,直接返回一個新的Promise對象昧互,這個對象中挽铁,直接調用onResolved方法
if(self.status === 'resolved') {
return promise2 = new Promise(function(resolve, reject) {
try {
var x = onResolved(self.data);
if(x instanceof Promise) {
x.then(resolve, reject);
}
resolve(x);
}
catch(err) {
reject(err);
}
});
}
// 當Promise對象狀態(tài)為rejected時,直接返回一個新的Promise對象敞掘,這個對象中直接調用onRejected方法
if(self.status === 'rejected') {
return promise2 = new Promise(function(resolve, reject) {
try {
var x = onRejected(self.data);
if(x instanceof Promise) {
x.then(resolve, reject);
}
}
catch(err) {
reject(err);
}
});
}
// 當Promise對象為pending時叽掘,直接返回一個新的Promise對象,這個對象中需要將onResolved以及onRejected方法存入相應的回調列表中
if(self.status === 'pending') {
return promise2 = new Promise(function(resolve, reject) {
self.onReslovedCallback.push(function(value) {
try {
var x = onResolved(self.data);
if(x instanceof Promise) {
x.then(resolve, reject);
}
}
catch(err) {
reject(err);
}
});
self.onRejectedCallback.push(function(reason) {
try {
var x = onRejected(self.data);
if(x instanceof Promise) {
x.then(resolve, reject);
}
}
catch(err) {
reject(err);
}
});
});
}
}
最后實現一下catch方法玖雁,很簡單更扁,直接調用then進行處理就可以了:
Promise.prototype.catch = function(onRejected) {
return this.then(null, onRejected);
};
至此,我們實現了一個簡單Promise對象赫冬,可以嘗試去使用一下(我們在node中進行測試浓镜,所以需要將其導出module.exports = Promise
):
var Promise = require('./promise');
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(1);
resolve();
}, 500);
});
p.then(function(resolve, reject) {
console.log(2);
resolve();
});
// 執(zhí)行結果
// 1
// 2
References