概覽
const PENDING = Symbol('PENDING');
const FULFILLED = Symbol('FULFILLED');
const REJECTED = Symbol('REJECTED');
class MyPromise {
constructor(fn) {}
then(successFn, failFn) {}
catch(failFn) {}
finally(finalFn){}
static resolve(val) {}
static reject(val) {}
static all(promiseArr) {}
static race(promiseArr) {}
}
Promise 內部維護着三種狀態 pending、fulfilled 和 rejected,狀態只能從 pending 轉變到 fulfilled,或從 pending 轉變到 rejected 且該轉變不可逆。
Promise 主要提供了三個實例方法 then,catch,finally,和4個靜態方法 resolve,reject,all,race。所有方法都都返回一個Promise對象。
構造函數
constructor(fn) {
this.fulfilledQueue = [];
this.rejectedQueue = [];
this._status = PENDING;
this._value = null;
// 執行成功隊列中的回調函數
const handleFulfilledQueue = () => {
while(this.fulfilledQueue.length) {
let fulfiledFn = this.fulfilledQueue.shift();
fulfiledFn(this._value);
};
};
// 執行失敗隊列中的回調函數
const handleRejectedQueue = () => {
while(this.rejectedQueue.length) {
let rejectedFn = this.rejectedQueue.shift();
rejectedFn(this._value);
};
};
// 完成狀態轉變,執行回調隊列中的回調函數
const _resolve = (val) => {
const fn = () => {
if(this._status !== PENDING) {
return;
}
if(val instanceof MyPromise) {
val.then((res) => {
this._status = FULFILLED;
this._value = res;
handleFulfilledQueue();
}, (err) => {
this._status = REJECTED;
this._value = err;
handleRejectedQueue();
});
} else {
this._status = FULFILLED;
this._value = val;
handleFulfilledQueue();
}
}
// 保證promise 回調函數一定是在同步任務之後執行;
setTimeout(fn, 0);
}
// 完成狀態Pending到REJECTED的轉變,執行rejected隊列中的回調函數
const _reject = (val) => {
const fn = () => {
if(this._status !== PENDING) {
return;
}
this._status = REJECTED;
this._value = val;
handleRejectedQueue();
}
setTimeout(fn, 0);
}
try { // 處理外部傳入函數執行異常
fn(_resolve, _reject);
} catch(e) {
return _reject(e);
}
}
Promise 構造函數接收一個函數執行器作爲參數,該執行器的兩個參數 _resolve、_reject均爲函數類型,由 Promise 內部實現。執行器在 Promise 構造函數中被立即執行。
注意: MyPromise 使用 Timeout 實現異步,使得 MyPromise 只能添加 macrotask,實際上原生的Promise 是 microtask
then 方法
then(successFn, failFn) {
return new MyPromise((resolve, reject) => {
// 執行成功時的回調函數
const handleSucess = (fn) => {
try {
if(typeof fn === 'function') {
const res = fn(this._value);
if(res instanceof MyPromise) {
res.then(resolve, reject);
} else {
resolve(res);
}
} else {
resolve(this._value)
}
} catch(e){
reject(e);
}
}
// 執行失敗時的回調函數
const handleFail = (fn) => {
try {
if(typeof fn === 'function') {
const res = fn(this._value);
if(res instanceof MyPromise) {
res.then(resolve, reject);
} else {
resolve(res);
}
} else {
reject(this._value);
}
} catch(e) {
reject(e);
}
}
switch(this._status){
case PENDING: // 異步任務尚未完成,將回調函數推入相應隊列
this.fulfilledQueue.push(() => {
handleSucess(successFn);
});
this.rejectedQueue.push(() => {
handleFail(failFn);
});
break;
case FULFILLED: // 異步任務成功完成,執行成功回調函數
handleSucess(successFn);
break;
case REJECTED: // 異步任務已失敗,執行失敗回調函數
handleFail(failFn);
break;
default:
console.log('Promise error status:', this._status);
break;
};
});
}
then 方法是 Promise 的一個主要方法,catch 和 finally 都可以用 then 來實現。當 Promise 的狀態已經流轉時,回調函數會立即被執行,當 Promise 還處於 Pending 狀態時,回調函數被推入相應隊列中等待執行。
完整代碼
class MyPromise {
constructor(fn) {
this.fulfilledQueue = [];
this.rejectedQueue = [];
this._status = PENDING;
this._value = null;
const handleFulfilledQueue = () => {
while(this.fulfilledQueue.length) {
let fulfiledFn = this.fulfilledQueue.shift();
fulfiledFn(this._value);
};
};
const handleRejectedQueue = () => {
console.log(this.rejectedQueue);
while(this.rejectedQueue.length) {
let rejectedFn = this.rejectedQueue.shift();
rejectedFn(this._value);
};
};
// 完成狀態轉變,執行回調隊列中的回調函數
const _resolve = (val) => {
const fn = () => {
if(this._status !== PENDING) {
return;
}
if(val instanceof MyPromise) {
val.then((res) => {
this._status = FULFILLED;
this._value = res;
handleFulfilledQueue();
}, (err) => {
this._status = REJECTED;
this._value = err;
handleRejectedQueue();
});
} else {
this._status = FULFILLED;
this._value = val;
handleFulfilledQueue();
}
}
setTimeout(fn, 0);
}
// 完成狀態Pending到REJECTED的轉變,執行rejected隊列中的回調函數
const _reject = (val) => {
const fn = () => {
if(this._status !== PENDING) {
return;
}
this._status = REJECTED;
this._value = val;
handleRejectedQueue();
}
setTimeout(fn, 0);
}
try { // 處理外部傳入函數執行異常
fn(_resolve, _reject);
} catch(e) {
return _reject(e);
}
}
then(successFn, failFn) {
return new MyPromise((resolve, reject) => {
// 執行成功時的回調函數
const handleSucess = (fn) => {
try {
if(typeof fn === 'function') {
const res = fn(this._value);
if(res instanceof MyPromise) {
res.then(resolve, reject);
} else {
resolve(res);
}
} else {
resolve(this._value)
}
} catch(e){
reject(e);
}
}
// 執行失敗時的回調函數
const handleFail = (fn) => {
try {
if(typeof fn === 'function') {
const res = fn(this._value);
if(res instanceof MyPromise) {
res.then(resolve, reject);
} else {
resolve(res);
}
} else {
reject(this._value);
}
} catch(e) {
reject(e);
}
}
switch(this._status){
case PENDING: // 異步任務尚未完成,將回調函數推入相應隊列
this.fulfilledQueue.push(() => {
handleSucess(successFn);
});
this.rejectedQueue.push(() => {
handleFail(failFn);
});
break;
case FULFILLED: // 異步任務成功完成,執行成功回調函數
handleSucess(successFn);
break;
case REJECTED: // 異步任務已失敗,執行失敗回調函數
handleFail(failFn);
break;
default:
console.log('Promise error status:', this._status);
break;
};
});
}
catch(failFn) {
return this.then(null, failFn);
}
finally(finalFn){
return this.then(finalFn, finalFn);
}
static resolve(val) {
if(val instanceof MyPromise) {
return val;
} else {
return new MyPromise((resolve, reject) =>{
resolve(val);
});
}
}
static reject(val) {
return new MyPromise((resolve, reject) => {
reject(val);
});
}
static all(promiseArr) {
return new Promise((resolve, reject) =>{
const len = promiseArr.length;
let count = 0;
let result = [];
for(let i = 0; i < len; i++) {
promiseArr[i].then((val) => {
count++;
result.push[val];
if(count === len){
resolve(result);
}
}, (err) => {
reject(err);
});
}
});
}
static race(promiseArr) {
return new Promise((resolve, reject) =>{
const len = promiseArr.length;
for(let i = 0; i < len; i++) {
promiseArr[i].then((val) => {
resolve(val);
}, (err) => {
reject(err);
});
}
});
}
}