咱們都知道,then
方法返回一個新的 promise
實例,這是實現鏈式調用的根本。javascript
爲了在 promise
狀態發生變化時(resolve
/ reject
被調用時)再執行 then
裏的函數,咱們使用一個 callbacks
數組先把傳給then的函數暫存起來,等狀態改變時再調用。java
那麼,怎麼保證後一個 then
裏的方法在前一個 then
(多是異步)結束以後再執行呢?數組
好比下面示例中,最後一個 then
應該在 2 秒後再打印,值爲 2promise
var p1 = new MyPromise((resolve, reject) => {
console.log('hhh')
setTimeout(() => {
resolve(1)
}, 1000);
}).then(res => {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(res+1)
}, 1000);
})
}).then(res => {
console.log(res);
return res;
})
複製代碼
將傳給 then
的函數和新 promise
的 resolve
一塊兒 push
到前一個 promise
的 callbacks
數組中,達到承前啓後的效果markdown
promise
完成後,調用其 resolve
變動狀態,在這個 resolve
裏會依次調用 callbacks
裏的回調,這樣就執行了 then
裏的方法了then
裏的方法執行完成後,返回一個結果,若是這個結果是個簡單的值,就直接調用新 promise
的 resolve
,讓其狀態變動,這又會依次調用新 promise
的 callbacks
數組裏的方法,循環往復。。若是返回的結果是個 promise
,則須要等它完成以後再觸發新 promise
的 resolve
,因此能夠在其結果的 then
裏調用新 promise
的 resolve
then(onFulfilled, onReject){
// 保存前一個promise的this
const self = this;
return new MyPromise((resolve, reject) => {
// 封裝前一個promise成功時執行的函數
let fulfilled = () => {
try{
const result = onFulfilled(self.value); // 承前
return result instanceof MyPromise? result.then(resolve, reject) : resolve(result); //啓後
}catch(err){
reject(err)
}
}
// 封裝前一個promise失敗時執行的函數
let rejected = () => {
try{
const result = onReject(self.reason);
return result instanceof MyPromise? result.then(resolve, reject) : reject(result);
}catch(err){
reject(err)
}
}
switch(self.status){
case PENDING:
self.onFulfilledCallbacks.push(fulfilled);
self.onRejectedCallbacks.push(rejected);
break;
case FULFILLED:
fulfilled();
break;
case REJECT:
rejected();
break;
}
})
}
複製代碼
then
裏的回調方法是同步註冊的,但註冊到了不一樣的 callbacks
數組中,由於每次 then
都返回新的 promise
實例(參考上面的例子和圖)callbacks
數組中提早註冊的回調那麼,什麼狀況下一個 callbaks
數組中會有多個回調呢?異步
好比這種:
p1
完成時,註冊在 p1
的 callbacks
中的函數依次執行
如下代碼 1 秒後打印出 1, 2 秒後打印出 2函數
var p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000);
})
var p2 =p1.then(res => { //p1完成時的回調1
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(res+1)
}, 1000);
})
}).then(res => {
console.log(res); // 2
return res+1;
})
p1.then(res => { // p1完成時的回調2
console.log(res); // 1
})
複製代碼
可是,若是這麼寫:ui
var p1 = new MyPromise((resolve, reject) => {
console.log('hhh')
setTimeout(() => {
resolve(1)
}, 1000);
}).then(res => {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(res+1)
}, 1000);
})
}).then(res => {
console.log(res); // 2
return res+1;
})
p1.then(res => {
console.log(res); // 3
})
複製代碼
最後一個 p1.then
是在最後纔打印出來的,由於 p1
的返回值是第三個 promise
,最後一個 then
裏的函數也是註冊進了第三個 promise
的 callbacks
中。this
// 定義三種狀態
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECT = 'REJECT';
class MyPromise {
constructor(fn){
// 初始化狀態
this.status = PENDING;
// 將成功、失敗的結果放在this上,便於then、catch訪問
this.value = null;
this.reason = null;
// 成功態、失敗態回調函數隊列,同步調用then時將對應態的函數註冊進去, 在狀態變動的時候調用
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if(this.status === PENDING){
this.status = FULFILLED;
this.value = value;
// 成功態回調函數依次執行
this.onFulfilledCallbacks.forEach(fn => fn(this.value))
}
}
const reject = (reason) => {
if(this.status === PENDING){
this.status = REJECT;
this.reason = reason;
// 失敗態回調函數依次執行
this.onRejectedCallbacks.forEach(fn => fn(this.reason))
}
}
// 生成實例後當即調用fn
// 把內部的resolve和reject傳入fn,用戶可調用resolve和reject
try{
fn(resolve, reject);
}catch(err){
// fn執行出錯,將錯誤內容用reject拋出去
reject(err)
}
}
then(onFulfilled, onReject){
// 實現值穿透 當then中傳入的不是函數,則這個promise返回上一個promise的值
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onReject = typeof onReject === 'function' ? onReject : reason => { throw new Error(reason) }
// 保存前一個promise的this
const self = this;
return new MyPromise((resolve, reject) => {
// 封裝前一個promise成功時執行的函數
let fulfilled = () => {
try{
const result = onFulfilled(self.value); // 承前
return result instanceof MyPromise? result.then(resolve, reject) : resolve(result); //啓後
}catch(err){
reject(err)
}
}
// 封裝前一個promise失敗時執行的函數
let rejected = () => {
try{
const result = onReject(self.reason);
return result instanceof MyPromise? result.then(resolve, reject) : reject(result);
}catch(err){
reject(err)
}
}
switch(self.status){
case PENDING:
self.onFulfilledCallbacks.push(fulfilled);
self.onRejectedCallbacks.push(rejected);
break;
case FULFILLED:
fulfilled();
break;
case REJECT:
rejected();
break;
}
})
}
// Promise.prototype.catch就是Promise.prototype.then(null, onRejected)的別名
catch(onRejected){
return this.then(null, onRejected);
}
static resolve(value){
// 若是是promise實例,直接返回
if(value instanceof MyPromise){
return value;
}else{
// 若是不是promise實例,返回一個新的promise對象,狀態爲fulfilled
return new MyPromise((resolve, reject) => resolve(value))
}
}
static reject(reason){
// Promise.reject方法的參數會原封不動地做爲reject的參數
return new MyPromise((resolve, reject) => reject(reason))
}
/** * Promise.all() 接受一個數組,返回一個promise對象 * 全部的promise狀態變爲FULFILLED,返回的promise狀態才變爲FULFILLED。 * 一個promise狀態變爲REJECTED,返回的promise狀態就變爲REJECTED。 * 數組成員不必定都是promise,須要使用Promise.resolve()處理。 */
static all(promiseArr){
const len = promiseArr.length;
const values = new Array(len);
let count = 0; // 記錄已經成功的promise個數
return new MyPromise((resolve, reject) => {
for(let i=0; i<len; i++){
// Promise.resolve()處理,確保每個都是promise實例
MyPromise.resolve(promiseArr[i]).then(
val => {
values[i] = val;
count++;
if(count === len) resolve(values); // 若是所有執行完,改變promise的狀態爲FulFilled
},
err => {
reject(err)
}
)
}
})
}
static race(promiseArr){
return new MyPromise((resolve, reject) => {
promiseArr.forEach(item => {
MyPromise,resolve(item).then(
val => resolve(val),
err => reject(err)
)
})
})
}
}
複製代碼