Promise是異步編程的⼀種解決⽅案。編程
Promise對象有如下兩個特色:數組
// 建立一個promise對象
var promise = new Promise(function(resolve, reject) {
...
if(/*異步操做成功*/){
resolve(data);
}else {
reject(err)
}
)
複製代碼
Promise構造函數接受⼀個函數做爲參數,該函數的兩個參數分別是resolve和reject。它們是兩個函數,由JavaScript引擎提供,不⽤⾃⼰部署。promise
Promise實例⽣成之後,能夠⽤then⽅法分別指定Resolved狀態和Rejected狀態的回調函數。bash
promise.then(function(value) {
// success
}, function(err){
// failure
})
複製代碼
then ⽅法能夠接受兩個回調函數做爲參數。成功回調和失敗回調,其中,第⼆個函數是可選的,不⼀定要提供。這兩個函數都接受Promise對象傳出的值做爲參數。異步
須要注意的是:異步編程
從Promise的使用來看能夠分爲兩部分:新建實例和調用實例的then方法。 因此咱們也能夠針對這兩部分分別實現:函數
首先從構造函數出發,根據上文對Promise的描述,咱們來實現這個Promise構造函數。ui
Promise構造函數接受⼀個函數做爲參數,該函數的兩個參數分別是resolve和reject。他們的做用是將state從Pending變爲fulfilled或者rejectedthis
function Promise (executor) {
this.state = 'pending';
this.data = undefined;
this.reason= undefined;
this.fn1Callbacks=[];
this.fn2Callbacks=[];
let resolve = value => {
if(this.state === 'pending'){
this.state = 'fulfilled';
this.data = value;
for(let i = 0; i<this.fn1Callbacks.length; i++){
self.fn1Callbacks[i](value);
}
}
};
let reject = reason => {
if(this.state === 'pending'){
this.state = 'rejected';
this.reason = reason;
for (let i = 0; i < self.fn2Callback.length; i++) {
self.fn2Callback[i](reason);
}
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
複製代碼
當Promise的狀態發生了改變,不管是成功或是失敗都會調用then方法。spa
Promise實例具備then方法,即then方法是定義在原型對象Promise.prototype上的。它的做用是爲Promise實例添加狀態改變時的回調函數並在異步完成時執行這個函數。
then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。所以能夠採用鏈式寫法,即then方法後面再調用另外一個then方法。
基於上面的討論咱們很容易得出結論:
下面咱們來看看promise實現
// then方法接收兩個參數,fn1,fn2,分別爲Promise成功或失敗後的回調
Promise.prototype.then = function(fn1, fn2) {
var self = this
var promise2
// 首先對入參 fn1, fn2作判斷
fn1 = typeof fn1 === 'function' ? fn1 : function(v) {}
fn2 = typeof fn2 === 'function' ? fn2 : function(r) {}
if (self.status === 'resolved') {
return promise2 = new Promise(function(resolve, reject) {
//todo
})
}
if (self.status === 'rejected') {
return promise2 = new Promise(function(resolve, reject) {
//todo
})
}
if (self.status === 'pending') {
return promise2 = new Promise(function(resolve, reject) {
// todo
})
}
}
複製代碼
首先是對輸入的成功回調和失敗回調進行類型判斷,明確是個函數再執行它,接下來是處理Promise中可能存在的有三種可能的狀態,咱們分三個if塊來處理,在裏面分別都返回一個new Promise。
因此,接下來的邏輯是:
根據上面的邏輯,填充下面代碼:
Promise.prototype.then = function(fn1, fn2) {
var self = this
var promise2
fn1 = typeof fn1 === 'function' ? fn1 : function(v) {}
fn2 = typeof fn2 === 'function' ? fn2 : function(r) {}
if (self.status === 'resolved') {
return promise2 = new Promise(function(resolve, reject) {
// 把 fn一、fn2 放在 try catch 裏面,畢竟 fn一、fn2 是用戶傳入的,報錯嘛,很常見
try {
var x = fn1(self.data)
// fn1 執行後,會有返回值,經過 resolve 注入到 then 返回的 promise 中
resolve(x)
} catch (e) {
reject(e)
}
})
}
if (self.status === 'rejected') {
return promise2 = new Promise(function(resolve, reject) {
try {
var x = fn2(self.data)
reject(x)
} catch (e) {
reject(e)
}
})
}
if (self.status === 'pending') {
return promise2 = new Promise(function(resolve, reject) {
this.fn1Callback.push(function(value){
try {
var x = fn1(self.data);
resolve(x)
} catch (e) {
reject(e)
}
})
this.fn2Callback.push(function(value) {
try {
var x = fn2(self.data);
reject(x)
} catch (e) {
reject(e)
}
})
})
}
}
複製代碼