Promise 有三种状态:PENDING、FULFILLED、REJECTED。
必须确保状态转换不可逆。
这是一个符合 Promise/A+ 规范的迷你版本,足以应对大部分手写题。
/**
* 实现一个Promise
* Promise 有三种状态:pending、fulfilled、rejected
* 1. 状态只能从 pending 变为 fulfilled 或者 rejected,一经改变,状态就不能再变化
* 2. 执行构造函数时,executor 立即执行
* 3. 执行 executor 出错,立马将状态改为 rejected
*/
class MyPromise {
// 创建一个构造函数,构造函数执行的时候 executor 立即执行
constructor(executor) {
this._status = MyPromise.PENDING;
this._value = undefined;
// 保存函数回调的队列
this._handlers = [];
try {
executor(this._resolve.bind(this), this._reject.bind(this));
} catch (error) {
// 任务出错了,直接将状态改为 rejected
this._reject(error);
}
}
/**
* 1. 表示当前任务完成
* 2. 改变 promise 状态为 fulfilled
* 3. 记录成功的数据
* @param {*} data
*/
_resolve(data) {
if (this._status !== MyPromise.PENDING) return;
this._status = MyPromise.FULFILLED;
this._value = data;
// 状态变化时,执行处理队列中的函数
this._runHandlers();
}
/**
* 1. 表示当前任务失败
* 2. 改变 promise 状态为 rejected
* 3. 记录失败的原因
* @param {*} reason
* @returns
*/
_reject(reason) {
if (this._status !== MyPromise.PENDING) return;
this._status = MyPromise.REJECTED;
this._value = reason;
// 状态变化时,执行处理队列中的函数
this._runHandlers();
}
/**
* 返回一个 Promise
* @param {*} onFulfilled
* @param {*} onRejected
* @returns
*/
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this._handlers.push({ executor: onFulfilled, state: MyPromise.FULFILLED, resolve, reject });
this._handlers.push({ executor: onRejected, state: MyPromise.REJECTED, resolve, reject });
// 如果状态已决,则直接执行
this._runHandlers();
});
}
/**
* 执行处理队列中的函数
*/
_runHandlers() {
// 如果状态还是 pending 挂起状态,不执行
if (this._status === MyPromise.PENDING) return;
// 每处理一个函数,都需要将其从队列中移除
while (this._handlers[0]) {
this._runHandler(this._handlers[0]);
this._handlers.shift();
}
}
_runHandler({ executor, state, resolve, reject }) {
runMicroTask(() => {
// 如果状态不一致,则不处理;
// onFulfilled 处理状态为 fulfilled 的函数
// onRejected 处理状态为 rejected 的函数
if (state !== this._status) return;
// 如果 onFulfilled 和 onRejected 不是函数,则需要将状态透传
if (typeof executor !== "function") {
this._status === MyPromise.FULFILLED ? resolve(this._value) : reject(this._value);
return;
}
try {
const result = executor(this._value);
// 如果返回值是 Promise,则等待其状态变化
if (isPromise(result)) {
result.then(resolve, reject);
} else {
// 如果返回值不是 Promise,则直接返回
resolve(result);
}
} catch (error) {
reject(error);
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(onFinally) {
return this.then(
(data) => {
onFinally();
return data;
},
(reason) => {
onFinally();
throw reason;
},
);
}
}
MyPromise.PENDING = "pending";
MyPromise.FULFILLED = "fulfilled";
MyPromise.REJECTED = "rejected";
function runMicroTask(fn) {
process.nextTick(fn);
}
function isPromise(obj) {
return !!(obj && typeof obj === "object" && typeof obj.then === "function");
}static resolve(data) {
if (data instanceof MyPromise) return data;
return new MyPromise((resolve, reject) => {
if (isPromise(data)) {
data.then(resolve, reject);
} else {
resolve(data);
}
});
}static reject(reason) {
return new MyPromise((_, reject) => {
reject(reason);
});
}/**
* 返回一个新的 Promise
* 所有 promise 成功后才返回成功,只要有一个失败就返回失败
* 返回结果的顺序需要保持一致
* @param {*} promises
*/
static all(promises) {
return new MyPromise((resolve, reject) => {
const result = [];
let count = 0;
let fulfilledCount = 0;
for (let pro of promises) {
// 记录当前的索引, 用于保证结果的顺序
let i = count;
count++;
// 用 resolve 包装一下,保证每个 promise 都是 promise 实例
MyPromise.resolve(pro).then((data) => {
result[i] = data;
fulfilledCount++;
if (fulfilledCount === count) {
resolve(result);
}
}, reject);
}
if (count === 0) {
resolve(result);
}
});
}/**
* 返回一个新的 Promise
* 等待所有的 promise 都 settled 后返回结果
* @param {*} promises
*/
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
const result = [];
let count = 0;
let fulfilledCount = 0;
for (let pro of promises) {
let i = count;
count++;
MyPromise.resolve(pro).then(
(data) => {
result[i] = { status: MyPromise.FULFILLED, value: data };
fulfilledCount++;
if (fulfilledCount === count) {
resolve(result);
}
},
(reason) => {
result[i] = { status: MyPromise.REJECTED, reason };
fulfilledCount++;
if (fulfilledCount === count) {
resolve(result);
}
},
);
}
if (count === 0) {
resolve(result);
}
});
}static race(promises) {
return new MyPromise((resolve, reject) => {
for (let pro of promises) {
MyPromise.resolve(pro).then(resolve, reject);
}
});
}queueMicrotask 或 setTimeout 来保证 then 回调在当前宏任务之后执行。onFulfilled,需要透传值 (x => x)。