已经很长时间没有写 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
等方法。
这个链接里面有另外一种实现方式,大同小异。