實現(xiàn) Promise
此代碼基本源于大佬在掘金上發(fā)的文章Promise實現(xiàn)原理(附源碼), 此文寫得相當詳細, 非常適合新手入門, 我這個僅是用于記錄自己寫的代碼
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
?
const isFunction = variable => typeof variable === 'function';
?
class MyPromise {
constructor(handler) {
if (!isFunction(handler)) {
throw new TypeError('MyPromise resolver undefined is not a function');
}
this._status = PENDING;
this._value = undefined;
// 因為 promise 可以被調用多次, 所以需要一個隊列保存對應調用
this._fullfilledQueue = [];
this._rejectedQueue = [];
?
try {
handler(this._resolve.bind(this), this._reject.bind(this));
} catch(e) {
this._reject(e);
}
}
_resolve(value) {
const fn = () => {
if (this._status !== PENDING) {
return;
}
const fulfilled = (val) => {
this._status = FULFILLED;
this._value = val;
let cb = undefined;
while (cb = this._fullfilledQueue.shift()) {
cb(val);
}
}
const rejected = (err) => {
this._status = REJECTED;
this._value = err;
let cb = undefined;
while (cb = this._rejectedQueue.shift()) {
cb(err);
}
}
// 當 value 為 promise 時, 當前 status 需等待 value 改變后才發(fā)生改變
if (value instanceof MyPromise) {
value.then((val) => {
fulfilled(val);
}, (err) => {
rejected(err);
})
} else {
fulfilled(value);
}
}
setTimeout(fn, 0);
}
_reject(err) {
const fn = () => {
if (this._status !== PENDING) {
return;
}
this._status = REJECTED;
this._value = err;
let cb = undefined;
while (cb = this._rejectedQueue.shift()) {
cb(err);
}
}
setTimeout(fn, 0);
}
then(onFulfilled, onRejected) {
return new MyPromise((onFulfilledNext, onRejectedNext) => {
const { _status, _value } = this;
let fulfilled = (value) => {
try {
// 如果當前 onFulfilled 不是一個函數(shù), 直接把 value 傳遞到下一次的 Promise
if (!isFunction(onFulfilled)) {
onFulfilledNext(value);
} else {
const res = onFulfilled(value);
// 如果當前 onFulfilled 返回一個 promise, 需要等到這個 promise 狀態(tài)發(fā)生改變才調用自身
if (res instanceof MyPromise) {
res.then(onFulfilledNext, onRejectedNext);
} else {
onFulfilledNext(res);
}
}
} catch(e) {
onRejectedNext(e);
}
}
let rejected = (error) => {
try {
if (!isFunction(onRejected)) {
onRejectedNext(error);
} else {
const res = onRejected(error);
if (res instanceof MyPromise) {
res.then(onFulfilledNext, onRejectedNext);
} else {
onRejectedNext(res);
}
}
} catch(e) {
onRejectedNext(e);
}
}
switch (_status) {
case PENDING:
this._fullfilledQueue.push(fulfilled);
this._rejectedQueue.push(rejected);
break;
case FULFILLED:
fulfilled(_value);
break;
case REJECTED:
rejected(_value);
break;
}
});
}
finally(cb) {
return this.then(
(value) => MyPromise.resolve(cb()).then(() => value),
(reason) => MyPromise.reject(cb()).then(() => reason),
);
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}
return new Promise((resolve) => resolve(value));
}
static reject(error) {
return new Promise((resolve, reject) => reject(error));
}
static all(promises) {
if (!Array.isArray(promises)) {
throw new TypeError('object is not iterable (cannot read property Symbol(Symbol.iterator))');
}
return new MyPromise((resolve, reject) => {
const values = [];
for (const [index, promise] of promises.entries()) {
// 數(shù)組參數(shù)可能不是 promise 需要先轉成 promise
this.resolve(promise).then((res) => {
values[index] = res;
if (values.length === promises.length) {
resolve(values);
}
}, (err) => {
reject(err);
});
}
})
}
static race(promises) {
if (!Array.isArray(promises)) {
throw new TypeError('object is not iterable (cannot read property Symbol(Symbol.iterator))');
}
return new MyPromise((resolve, reject) => {
for (const promise of promises) {
// 數(shù)組參數(shù)可能不是 promise 需要先轉成 promise
this.resolve(promise).then((res) => {
resolve(res);
}, (err) => {
reject(err);
});
}
});
}
}