前言
在工作中每天都在写 Promise,感觉自己对 Promise 很了解,今天看了一下 Promise 规范才发现有一些很基本的细节一直被我忽略了。今天就让我们跟着Promise A+规范来重新学习一下 Promise。
规范
手写 Promise 之前我们首先要了解我们需要实现哪些功能。
完整版参考:Promise/A+
MDN:Promise
executor 函数
功能点
- Promise 的状态只能是这三种之一: pending, fulfilled, 或者 rejected。
- 当状态是 pending 可以变成 fulfilled 或者 rejected。
- 当状态是 fulfilled 时,状态不能被改变,并且要有一个 value。
- 当状态是 rejected 时,状态不能被改变,并且要有一个 reason。
- executor 函数需要被立即执行。举个栗子
new Promise((resolve, reject) => {
// 这里的代码需要立即执行
setTimeout(() => { resolve("foo"); }, 300);
});
实现
class SzzPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
const resolve = (v) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = v;
}
};
const reject = (v) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = v;
}
};
executor(resolve, reject);
}
}
then 函数
功能点
- then 函数有两个参数,这两个参数都是可选的,我们先假设这两个参数叫做 onFulfilled 和 onRejected。
- onFulfilled 和 onRejected 都是一个函数。
- onFulfilled 会在 Promise 状态变为 fulfilled 之后执行,并且只能被执行一次。
- onRejected 会在 Promise 状态变为 fulfilled 之后执行,并且只能被执行一次。
- 同一个 Promise 的 then 可以被调用多次,举个例子
const p1 = new Promise((resolve, reject) => {
// 这里的代码需要立即执行
setTimeout(() => { resolve("foo"); }, 300);
});
// 同一个 Promise 的 then 可以被调用多次
p1.then(console.log);
p1.then(console.log);
p1.then(console.log);
实现
class SzzPromise {
constructor(executor) {
this.state = 'pending';
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
this.value = undefined;
this.reason = undefined;
const resolve = (v) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = v;
this.onFulfilledCallbacks.forEach((cb) => cb(v));
}
};
const reject = (v) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = v;
this.onRejectedCallbacks.forEach((cb) => cb(v));
}
};
executor(resolve, reject);
}
then(onFulfilled, onRejected) {
this.onFulfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
}
}
function resolveWithTryCatch(fn, value, resolve, reject) {
try {
const result = fn(value);
resolve(result);
} catch (e) {
reject(e);
}
}
class SzzPromise {
constructor(executor) {
this.state = 'pending';
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
this.value = undefined;
this.reason = undefined;
const resolve = (v) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = v;
this.onFulfilledCallbacks.forEach((cb) => cb(v));
}
};
const reject = (v) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = v;
this.onRejectedCallbacks.forEach((cb) => cb(v));
}
};
executor(resolve, reject);
}
then(onFulfilled, onRejected) {
const fulfilledFn = typeof onFulfilled === 'function' ? onFulfilled : (v) => v;
const rejectedFn = typeof onRejected === 'function' ? onRejected : (v) => { throw v; };
return new SzzPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
resolveWithTryCatch(fulfilledFn, this.value, resolve, reject);
} else if (this.state === 'rejected') {
resolveWithTryCatch(rejectedFn, this.reason, resolve, reject);
} else if (this.state === 'pending') {
this.onFulfilledCallbacks.push((v) => {
resolveWithTryCatch(fulfilledFn, v, resolve, reject);
});
this.onRejectedCallbacks.push((v) => {
resolveWithTryCatch(rejectedFn, v, resolve, reject);
});
}
});
}
}
结语
以上就是我们的所有内容,我们只实现了Promise的主体功能,还有很多细节需要优化。 如果想要知道如何写出能够100%通过Promise单元测试的实现可以参考这篇文章