3. 实现 then 链式调用 & then 穿透 & 异步操作 & 错误捕获
- PS:then 穿透指当某个 then 操作中没有对应的回调处理,把当前 promise 的值透传给一下个 then. 例如:
- 问题暴露:
- 未实现多个 then 间的链式调用
- 未实现 then 穿透
- 未实现 resolve & reject 异步
- 未捕获所有回调函数可能出现的错误,并传递给下一个 then 的 onReject 回调
- 解决问题:
- then 中返回一个新的 promise
- 对 then 中接收的参数做兼容处理
- 调用回调时,通过 setTimeout 包裹处理
- 通过 try catch 实现错误捕获,然后调用 promise 中的 reject
// 三种状态 const PENDING = "pending"; const RESOLVED = "resolved"; const REJECTED = "rejected"; // promise 接收⼀个函数参数,该函数会⽴即执⾏ class MyPromise { constructor(fn) { this.value; this.status = PENDING;// 默认状态 this.onResolveCallBack = [];// 缓存 onResolve this.onRejectCallBack = [];// 缓存 onReject // 这里使用 try catch 捕获中可能发生的错误 try { // 这里必须要绑定 this,否则在外部调用时 this 就不会执行当前实例 fn(this.resolve.bind(this), this.reject.bind(this)); } catch (error) { this.reject.bind(this, error); } } resolve(value) { if (this.status === PENDING) { this.value = value; this.status = RESOLVED; // setTimeout 为了保证异步顺序执行 setTimeout(() => { // 遍历调用 onResolveCallBack this.onResolveCallBack.forEach(r => r()); }); } } reject(reason) { if (this.status === PENDING) { this.value = reason; this.status = REJECTED; // setTimeout 为了保证异步顺序执行 setTimeout(() => { // 遍历调用 onRejectCallBack this.onRejectCallBack.forEach(r => r()); }); } } } MyPromise.prototype.then = function (onResolve, onReject) { // 保证 onResolve & onReject 为函数 // 主要是为了 .then().then((v)=>v) 的情况,称之为 then 穿透 onResolve = typeof onResolve === 'function' ? onResolve : (v) => v; onReject = typeof onReject === 'function' ? onReject : (v) => v; // 这里是为了实现链式操作 return new MyPromise((resovle, reject) => { // 当前 promise 实例调用了 resolve if (this.status === RESOLVED) { // setTimeout 为了保证异步顺序执行 setTimeout(() => { try { let result = onResolve(this.value); resovle(result); // 下一个 promise 的状态为 fulfilled } catch (error) { reject(error); } }); } // 当前 promise 实例调用了 reject if (this.status === REJECTED) { // setTimeout 为了保证异步顺序执行 setTimeout(() => { try { let result = onReject(this.value); resovle(result); // 下一个 promise 的状态为 fulfilled } catch (error) { reject(error); } }); } // 当前 promise 状态为 pending,把当前的 onResolve & onReject 缓存起来 if (this.status === PENDING) { this.onResolveCallBack.push(() => { try { let result = onResolve(this.value); resovle(result); // 下一个 promise 的状态为 fulfilled } catch (error) { reject(error); } }); this.onRejectCallBack.push(() => { try { let result = onReject(this.value); resovle(result); // 下一个 promise 的状态为 fulfilled } catch (error) { reject(error); } }); } }); } 复制代码
5. then 中的逻辑判断
- then 手动返回 promise 实例,下一个 then 操作要依据返回的 promise 状态
- 不允许返回当前 promise 实例本身
- 抽取重复逻辑
// 三种状态 const PENDING = "pending"; const RESOLVED = "resolved"; const REJECTED = "rejected"; // promise 接收⼀个函数参数,该函数会⽴即执⾏ class MyPromise { constructor(fn) { this.value; this.status = PENDING;// 默认状态 this.onResolveCallBack = [];// 缓存 onResolve this.onRejectCallBack = [];// 缓存 onReject // 这里使用 try catch 捕获中可能发生的错误 try { // 这里必须要绑定 this,否则在外部调用时 this 就不会执行当前实例 fn(this.resolve.bind(this), this.reject.bind(this)); } catch (error) { this.reject.bind(this, error); } } resolve(value) { if (this.status === PENDING) { this.value = value; this.status = RESOLVED; // setTimeout 为了保证异步顺序执行 setTimeout(() => { // 遍历调用 onResolveCallBack this.onResolveCallBack.forEach(r => r()); }); } } reject(reason) { if (this.status === PENDING) { this.value = reason; this.status = REJECTED; // setTimeout 为了保证异步顺序执行 setTimeout(() => { // 遍历调用 onRejectCallBack this.onRejectCallBack.forEach(r => r()); }); } } } MyPromise.prototype.then = function (onResolve, onReject) { // 保证 onResolve & onReject 为函数 // 主要是为了 .then().then((v)=>v) 的情况,称之为 then 穿透 onResolve = typeof onResolve === 'function' ? onResolve : (v) => v; onReject = typeof onReject === 'function' ? onReject : (v) => v; // 这里是为了实现链式操作 let promise = new MyPromise((resolve, reject) => { // 当前 promise 实例调用了 resolve if (this.status === RESOLVED) { // setTimeout 为了保证异步顺序执行 setTimeout(() => { let result = onResolve(this.value); transferPromiseResult(promise, result, resolve, reject); }); } // 当前 promise 实例调用了 reject if (this.status === REJECTED) { // setTimeout 为了保证异步顺序执行 setTimeout(() => { let result = onReject(this.value); transferPromiseResult(promise, result, resolve, reject); }); } // 当前 promise 状态为 pending,把当前的 onResolve & onReject 缓存起来 if (this.status === PENDING) { this.onResolveCallBack.push(() => { let result = onResolve(this.value); transferPromiseResult(promise, result, resolve, reject); }); this.onRejectCallBack.push(() => { let result = onReject(this.value); transferPromiseResult(promise, result, resolve, reject); }); } }); return promise; } // 将上一次的 promise 的值,传递给下一个 then function transferPromiseResult(promise, result, resolve, reject) { // 为了处理当前的 promise 实例,在当前的 then 被返回 if (promise === result) { throw new TypeError('Chaining cycle detected for promise #<MyPromise>'); } try { // 如果上一个 then 返回的是 MyPromise 的实例 && 不是同一个 promise 实例 // 那只需要把 MyPromise 中的处理好的返回值传递给一下 then 即可 if (result instanceof MyPromise) { result.then(resolve, reject); } else { // 正常结果,传给下一个 then resolve(result); } } catch (error) { reject(error); } } 复制代码
6. 实现 MyPromise.all() & MyPromise.race()
- 上面我们实现了大部分的功能,这里的 all 和 race 都只需要基于已有功能实现即可.
- all --> 接收多个 promise 的数组,当全部 promise 执行完,且状态都为 fulfilled,则返回结果集,否则返回失败的结果.
- race --> 接收多个 promise 的数组,结果取最先完成的 promise 的结果,无论状态是 fulfilled 或者是 rejected.
// 三种状态 const PENDING = "pending"; const RESOLVED = "resolved"; const REJECTED = "rejected"; // promise 接收⼀个函数参数,该函数会⽴即执⾏ class MyPromise { constructor(fn) { this.value; this.status = PENDING; this.onResolveCallBack = []; this.onRejectCallBack = []; // 执行传入fn try { fn(this.resolve.bind(this), this.reject.bind(this)); } catch (error) { // 发生错误时,统一用 reject 方法处理 this.reject(error); } } // 实例方法 resolve resolve(value) { if (this.status === PENDING) { this.value = value; this.status = RESOLVED; // setTimeout 保证异步执行 setTimeout(() => { // 执行在 then 中存储的回调 try { this.onResolveCallBack.forEach((fn) => fn && fn(this.value)); } catch (error) { this.onRejectCallBack.forEach((fn) => fn && fn(error)); } }); } } // 实例方法 reject reject(reason) { if (this.status === PENDING) { this.value = reason; this.status = REJECTED; // setTimeout 保证异步执行 setTimeout(() => { // 执行在 then 中存储的回调 this.onRejectCallBack.forEach((fn) => fn && fn(this.value)); }); } } // 静态方法 resolve static resolve(value) { return new MyPromise((resolve, reject) => { if (value instanceof MyPromise) { value.then(resolve, reject); } else { resolve(value); } }); } // 静态方法 reject static reject(value) { console.log(value); return new MyPromise((resolve, reject) => { if (value instanceof MyPromise) { value.then(resolve, reject); } else { reject(value); } }); } // 静态方法 all static all(promiseArr) { // 记录每个成功的 promise 结果 const resolveResultArr = []; return new MyPromise((resolve, reject) => { promiseArr.forEach(promise => { promise.then(value => { resolveResultArr.push(value); // 当两者的长度一致,表明所有 promise 执行完成,并结果都是成功的 if (promiseArr.length === resolveResultArr.length) { resolve(resolveResultArr); } }, reason => { // 只要一个 promise 失败,就是失败 reject(reason); }); }); }); } // 静态方法 race static race(promiseArr) { return new MyPromise((resolve, reject) => { promiseArr.forEach(promise => { promise.then(value => { resolve(value); }, reason => { reject(reason); }); }); }); } } MyPromise.prototype.then = function (onResolve, onReject) { // 保证 onResolve & onReject 为函数 // 主要是为了 .then().then((v)=>v) 的情况,称之为 then 穿透 onResolve = typeof onResolve === 'function' ? onResolve : (v) => v; onReject = typeof onReject === 'function' ? onReject : (v) => v; let promise = new MyPromise((resolve, reject) => { if (this.status === RESOLVED) { setTimeout(() => { // 把上一个 then 中返回的值保存 result let result = onResolve(this.value); // 传递值下一个 then transferPromiseResult(promise, result, resolve, reject); }); } if (this.status === REJECTED) { setTimeout(() => { // 相当于把上一个 then 中返回的值保存 result let result = onReject(this.value); // 传递值下一个 then transferPromiseResult(promise, result, resolve, reject); }); } // 在这里通过数组存储对应的回调,方便在状态改变之后进行调用 if (this.status === PENDING) { this.onResolveCallBack.push(() => { // 把上一个 then 中返回的值保存 result let result = onResolve(this.value); // 传递值下一个 then transferPromiseResult(promise, result, resolve, reject); }); this.onRejectCallBack.push(() => { // 相当于把上一个 then 中返回的值保存 result let result = onReject(this.value); // 传递值下一个 then transferPromiseResult(promise, result, resolve, reject); }); } }); return promise; } // 将上一次的 promise 的值,传递给下一个 then function transferPromiseResult(promise, result, resolve, reject) { // 为了处理当前的 promise 实例,在当前的 then 被返回 if (promise === result) { throw new TypeError('Chaining cycle detected for promise #<MyPromise>'); } try { // 如果上一个 then 返回的是 MyPromise 的实例 && 不是同一个 promise 实例 // 那只需要把 MyPromise 中的处理好的返回值传递给一下 then 即可 if (result instanceof MyPromise) { result.then(resolve, reject); } else { // 正常结果,传给下一个 then resolve(result); } } catch (error) { reject(error); } } 复制代码