skip to content
FaiChou's blog

JS Promise

/ 4 min read

已经很长时间没有写 JS 了,现在写一个 JS Promise 的简单实现。

版本1

class SimplePromise {
constructor(executor) {
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
const resolve = (value) => {
if (this.status === 'pending') {
this.status = 'fulfilled';
this.value = value;
}
};
const reject = (reason) => {
if (this.status === 'pending') {
this.status = 'rejected';
this.reason = reason;
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
if (this.status === 'fulfilled') {
onFulfilled(this.value);
}
if (this.status === 'rejected') {
onRejected(this.reason);
}
}
}

这个版本大概能看明白 Promise 需要的参数,以及它的执行时机。但是有一个问题,当调用 then 方法传入的函数时候,如果异步某一执行完成,此时还在 pending 状态,那这个函数不会再被执行。所以需要优化一下,将需要当状态改变后执行的函数存起来,并且 Promise 可以无限被 then 所以要存到数组中。

版本2

class SimplePromise {
constructor(executor) {
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === 'pending') {
this.status = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(cb => cb(this.value));
}
};
const reject = (reason) => {
if (this.status === 'pending') {
this.status = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(cb => cb(this.reason));
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
if (this.status === 'fulfilled') {
onFulfilled(this.value);
} else if (this.status === 'rejected') {
onRejected(this.reason);
} else if (this.status === 'pending') {
this.onFulfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
}
}
}

在这个版本中,已经可以简单运行并执行测试一下:

const p = new SimplePromise(resolve => setTimeout(resolve, 1000, Math.random()))
setTimeout(() => {
p.then(v => console.log(`inner: ${v}`))
}, 3000)
p.then(v => console.log(`outer: ${v}`))

最终的执行是这样的:

1秒后打印:outer: 0.5220189262043281
再过2秒打印:inner: 0.5220189262043281

但它仍然欠缺一点东西,如果 resolve 函数的返回值仍然是一个 Promise, 那它应该继续自动执行这个 Promise;如果不是 Promise 而是一个准确的值,那需要保证是异步。所以有了版本3

版本3

class SimplePromise {
constructor(executor) {
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (value instanceof SimplePromise) {
return value.then(resolve, reject);
}
setTimeout(() => {
if (this.status === 'pending') {
this.status = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(cb => cb(this.value));
}
}, 0);
};
const reject = (reason) => {
setTimeout(() => {
if (this.status === 'pending') {
this.status = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(cb => cb(this.reason));
}
}, 0);
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
if (this.status === 'fulfilled') {
setTimeout(() => onFulfilled(this.value), 0);
} else if (this.status === 'rejected') {
setTimeout(() => onRejected(this.reason), 0);
} else if (this.status === 'pending') {
this.onFulfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
}
}
}

当然真正的 Promise 还是要继续优化,比如链式调用的 then 和错误处理,以及 Promise.all 等方法。

这个链接里面有另外一种实现方式,大同小异。