但大体上,考虑了上面这些步骤实现,基本功能也差不多了,重要的是状态变更这个的处理要考虑全一点,网上一些文章的实现版,这个是漏掉考虑的
还有当面试遇到让你手写实现 Promise 时不要慌,可以按着这篇的思路,先把 Promise 的基本用法回顾一下,然后回想一下它支持的功能,再然后心里有个大概的骨架,其实无非也就是几个内部变量、构造函数、状态变更函数、then 函数这几块而已,但死记硬背并不好,有个思路,一步步来,总能回想起来
源码源码补上了 catch,resolve 等其他方法的实现,这些其实都是基于 Promise 基本功能上的一层封装,方便使用
class Promise { /** * 构造函数负责接收并执行一个 task 处理函数,并将自己内部提供的两个状态变更处理的函数传递给 task,同时将当前 promise 状态置为 PENDING(执行中) */ constructor(task) { /* 三种状态 */ this.PENDING = 'pending'; this.RESOLVED = 'resolved'; this.REJECTED = 'rejected'; /* 成功的回调 */ this._resolvedCallback = []; /* 失败的回调 */ this._rejectedCallback = []; // 1. 将当前状态置为 PENDING this._status = this.PENDING; // 参数类型校验 if (!(task instanceof Function)) { throw new TypeError(`${task} is not a function`); } try { // 2. 调用 task 处理函数,并将状态变更通知的函数传递过去,需要注意 this 的处理 task(this._handleResolve.bind(this), this._handleReject.bind(this)); } catch (e) { // 3. 如果 task 处理函数发生异常,当做失败来处理 this._handleReject(e); } } /** * resolve 的状态变更处理 */ _handleResolve(value) { if (this._status === this.PENDING) { if (value instanceof Promise) { // 1. 如果 value 是 Promise,那么等待 Promise 状态结果出来后,再重新做状态变更处理 try { // 这里之所以不需要用 bind 来注意 this 问题是因为使用了箭头函数 // 这里也可以写成 value.then(this._handleResole.bind(this), this._handleReject.bind(this)) value.then(v => { this._handleResolve(v); }, err => { this._handleReject(err); }); } catch(e) { this._handleReject(e); } } else if (value && value.then instanceof Function) { // 2. 如果 value 是具有 then 方法的对象时,那么将这个 then 方法当做 task 处理函数,把状态变更的触发工作交由 then 来处理,注意 this 的处理 try { const then = value.then; then.call(value, this._handleResolve.bind(this), this._handleReject.bind(this)); } catch(e) { this._handleReject(e); } } else { // 3. 其他类型,状态变更、触发成功的回调 this._status = this.RESOLVED; this._value = value; setTimeout(() => { this._resolvedCallback.forEach(callback => { callback(); }); }); } } } /** * reject 的状态变更处理 */ _handleReject(value) { if (this._status === this.PENDING) { this._status = this.REJECTED; this._value = value; setTimeout(() => { this._rejectedCallback.forEach(callback => { callback(); }); }); } } /** * then 方法,接收两个可选参数,用于注册回调处理,所以类型也是函数,且有一个参数,接收 Promise 执行结果,同时可返回任意值,作为新 Promise 的执行结果 */ then(onResolved, onRejected) { // then 方法返回一个新的 Promise,新 Promise 的状态结果依赖于回调函数的返回值 return new Promise((resolve, reject) => { // 对回调函数进行一层封装,主要是因为回调函数的执行结果会影响到返回的新 Promise 的状态和结果 const _onResolved = () => { // 根据回调函数的返回值,决定如何处理状态变更 if (onResolved && onResolved instanceof Function) { try { const result = onResolved(this._value); resolve(result); } catch(e) { reject(e); } } else { // 如果传入非函数类型,则将上个Promise结果传递给下个处理 resolve(this._value); } }; const _onRejected = () => { if (onRejected && onRejected instanceof Function) { try { const result = onRejected(this._value); resolve(result); } catch(e) { reject(e); } } else { reject(this._value); } }; // 如果当前 Promise 状态还没变更,则将回调函数放入队列里等待执行 // 否则直接创建微任务来处理这些回调函数 if (this._status === this.PENDING) { this._resolvedCallback.push(_onResolved); this._rejectedCallback.push(_onRejected); } else if (this._status === this.RESOLVED) { setTimeout(_onResolved); } else if (this._status === this.REJECTED) { setTimeout(_onRejected); } }); } catch(onRejected) { return this.then(null, onRejected); } static resolve(value) { if (value instanceof Promise) { return value; } return new Promise((reso) => { reso(value); }); } static reject(value) { if (value instanceof Promise) { return value; } return new Promise((reso, reje) => { reje(value); }); } } 测试网上有一些专门测试 Promise 的库,可以直接借助这些,比如:promises-tests
我这里就举一些基本功能的测试用例: