你能白瞟到的最“善解人意”的Promise实现
2020/7/6 11:27:42
本文主要是介绍你能白瞟到的最“善解人意”的Promise实现,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前沿
俗话说站在前辈巨擘的肩上,才能看的更远。在拜读了巨擘大咖们写的promise实现之后,全身经络通畅,如被先辈们用金手指点中了百会穴。至此以后,运行大小周天比往常更熟练了几分。然而,肩井穴,涌泉穴,每日亥时,都会隐隐作痛。思来想去,大概时先前巨擘的文章精妙,我一时无法全部领悟其中奥妙。固苦心感悟,方得此篇。不敢与前辈比肩,只当部分补充而已
直男不懂铺垫,所以直接干
这里我们用es6来实现,这样结构比较明显,如果有对es6不太熟悉的朋友,可以看看阮一峰老师的ECMAScript 6 入门
class myPromise { constructor(executor){ this.value = null; this.reason = null; const resolve = value =>{ this.value = value; } const reject = reason => { this.reason = reason; } try { executor(resolve,reject) } catch (e) { reject(e) } } then(onFulfilled,onRejected){ onFulfilled(this.value) onRejected(this.reason) } } 复制代码
代码解析:
myPromise是一个构造函数,参数是一个高阶函数,接受两个内部函数resolve,reject myPromise的实例都可以调用then方法,then方法的第一个参数接受resolve的返回,第二个参数接受reject的返回
学武功的第一步是(自宫)对比
起手式
观察后发现:我们实现的myPormise和Promise运行的结果一致(good guy!),只是有一个小问题,我们是先调用的p1的then,但是p1的then返回却是在p2的then返回之后。我们保留疑问,继续淦!!!
resolve/reject的单一性
意思就是当一个promise中的resolve或者reject执行了之后,那之后resolve/reject都不再执行
![](/upload/202007/06/202007061127364790.png)
观察之后,发现这就不对了
别人家的promise只返回了一个'p1-resolve',而咱们家的promise返回了'p2-resolve2'和'p2-reject1' 别家的promise和咱们家的promise不一样就算了,咋还少了一个'p2-resolve1'呢?这里的原因是reslove方法里面,我们用一个内部变量this.value保存了resolve的值,当执行resolve('p2-resolve1')之后,再执行resolve('p2-resolve2')时,this.value就被后者重新赋值了。然后再执行到then函数时,自然而然'p2-resolve1'就消失了。 怎么修改呢? 这里我们引入一个内部状态的概念来处理这个问题,初始状态我们设置为'pending',它只有一次改变状态的机会,它可以变成pending->fulfilled或者pending->rejected,一旦改变之后,就不在变化。(是不是像极了宝可梦的进化)。 另外为了保证resolve/reject执行的唯一性,当状态不在是pending时,resolve/reject就不执行
所以...(就决定是你了,皮卡丘!!!)
class myPromise { constructor(executor){ + this.state = 'pending'; //内部状态为pending,resolve,reject this.value = null; this.reason = null; const resolve = value => { + if(this.state === 'pending'){ + this.state = 'fulfilled'; this.value = value; + } } const reject = reason => { + if(this.state === 'pending'){ + this.state = 'rejected'; this.reason = reason; + } } try { executor(resolve,reject) } catch (e) { reject(e) } } then(onFulfilled,onRejected){ + if(this.state === 'fulfilled'){ onFulfilled(this.value) + } + if(this.state === 'rejected') { onRejected(this.reason) + } } } 复制代码
修改之后,再观察,咱们家的promise又正常了一些。
promise的异步执行
我们稍微清理一下我们的测试代码,使它看上去清爽自然
清理完之后。我们加上异步
通过观察,我们发现,我们的promise没有任何打印
仔细思考之后,我们可以想到,当resolve还没有执行的时候,then函数已经执行了,而这时的state为'pending',所以then函数里面不会有任何执行 我们怎么处理这种情况呢?首先可以想到,当resolve/reject的时候,这个时候执行then时的state为'pending',而这个时候,我们不知道之后到底时执行resolve呢?还是reject,所以我们只有将所有的then的所有的参数(onFulfilled/onRejected)都暂存起来,以待之后的state改变之后执行对应的方法(onFulfilled/onRejected) 当状态改变之后,立即执行暂存的对应的方法
基于上面所说,我们修改我们的promise
class myPromise { constructor(executor){ this.state = 'pending'; //内部状态为pending,resolve,reject this.value = null; this.reason = null; + this.onFulfilledCallbacks = []; + this.onRejectedCallbacks = []; const resolve = value =>{ if(this.state === 'pending'){ this.state = 'fulfilled'; this.value = value; + this.onFulfilledCallbacks.forEach(fn=>fn(value)) } } const reject = reason => { if(this.state === 'pending'){ this.state = 'rejected'; this.reason = reason; + this.onRejectedCallbacks.forEach(fn=>fn(reason)) } } try { executor(resolve,reject) } catch (e) { reject(e) } } then(onFulfilled,onRejected){ if(this.state === 'fulfilled'){ onFulfilled(this.value) } if(this.state === 'rejected') { onRejected(this.reason) } + if(this.state === 'pending') { + this.onFulfilledCallbacks.push(onFulfilled) + this.onRejectedCallbacks.push(onRejected) + } } } 复制代码
修改之后,我们看看结果
观察之后,发现我们的promise能够正常的显示then回调了,而且还有意外收获,仔细观察我们发现,p1.then和p2.then打印的顺序和调用时的顺序一致了!!!
同步异步一致性
不论promise里面的resolve/reject是同步或者异步,我们都希望then返回的执行表现一致 我们创建一个执行对比
经过观察,我们可以发现
别人家的promise,不论resolve是同步的还是异步的,then返回都是异步的 咱们家的promise,当resolve是异步的,then返回是异步的,当resolve是同步的返回就是同步的
那么怎么改呢?我们的目的是要保持then的执行一致,所以只能把全部的then修改成异步的,原因在上一节已经说明了 我们来修改一下咱们家的promise
class myPromise { constructor(executor) { this.state = 'pending'; //内部状态为pending,resolve,reject this.value = null; this.reason = null; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = value => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; this.onFulfilledCallbacks.forEach(fn => fn(value)) } } const reject = reason => { if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; this.onRejectedCallbacks.forEach(fn => fn(reason)) } } try { executor(resolve, reject) } catch (e) { reject(e) } } then(onFulfilled, onRejected) { if (this.state === 'fulfilled') { + setTimeout(()=>{ onFulfilled(this.value) + }) } if (this.state === 'rejected') { + setTimeout(()=>{ onRejected(this.reason) + }) } if (this.state === 'pending') { + this.onFulfilledCallbacks.push((value)=>setTimeout(()=>{onFulfilled(value)})) + this.onRejectedCallbacks.push((reason)=>setTimeout(()=>{onRejected(reason)})) } } } 复制代码
然后来看看执行
现在咱们家的promise就更像别人家的了
为什么是数组
细心的小伙伴会发现this.onFulfilledCallbacks和this.onRejectedCallbacks是数组,在then方法里面,当state === 'pending'时,我们把onFulfilled和onRejected添加再数组进数组,而不是直接赋值给this.onFulfilledCallbacks/this.onRejectedCallbacks。会觉得这里直接赋值好像也没有什么问题。
我们修改一下我们promise直接用变量存储
class myPromise { constructor(executor) { this.state = "pending"; //内部状态为pending,resolve,reject this.value = null; this.reason = null; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === "pending") { this.state = "fulfilled"; this.value = value; - this.onFulfilledCallbacks.forEach((fn) => fn(value)); + this.onFulfilledCallbacks(value); } }; const reject = (reason) => { if (this.state === "pending") { this.state = "rejected"; this.reason = reason; this.onRejectedCallbacks.forEach((fn) => fn(reason)); } }; try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFulfilled, onRejected) { if (this.state === "fulfilled") { setTimeout(() => { onFulfilled(this.value) }) } if (this.state === "rejected") { setTimeout(() => { onRejected(this.reason) }) } if (this.state === "pending") { - this.onFulfilledCallbacks.push((value)=>setTimeout(()=>{onFulfilled(value)})); + this.onFulfilledCallbacks = (value)=>setTimeout(()=>{onFulfilled(value)}); this.onRejectedCallbacks.push(onRejected); } } } 复制代码
![](/upload/202007/06/202007061127374038.png)
经过观察我们发现:
别人家的promise,两个then回调的onFulfilled都正常执行了,咱们家的只执行了第二个then回调的 咱们家的promise的问题是,第二个then执行的时候,覆盖了第一个then的onFulfilledCallbacks赋值。所以这里只会执行第二个then回调的onFulfilled
我们把代码回滚到上一节,然后进入下一节
链式调用
then方法无论何时都返回一个promise实例
我们仔细观察一下
别人家的promise是执行了第一个then方法之后,又成功的执行了第二个then方法 咱们家的promise是执行了第一个then方法之后,第二个then方法就报错了 因为咱们家的promise的then方法没有返回一个promise对象
我们按着我们的分析来修改一下我们的promise
class myPromise { constructor(executor) { this.state = "pending"; //内部状态为pending,resolve,reject this.value = null; this.reason = null; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === "pending") { this.state = "fulfilled"; this.value = value; this.onFulfilledCallbacks.forEach((fn) => fn(value)); } }; const reject = (reason) => { if (this.state === "pending") { this.state = "rejected"; this.reason = reason; this.onRejectedCallbacks.forEach((fn) => fn(reason)); } }; try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFulfilled, onRejected) { if (this.state === "fulfilled") { setTimeout(() => { onFulfilled(this.value) }) } if (this.state === "rejected") { setTimeout(() => { onRejected(this.reason) }) } if (this.state === "pending") { this.onFulfilledCallbacks.push((value)=>setTimeout(()=>{onFulfilled(value)})); this.onFulfilledCallbacks = (value)=>setTimeout(()=>{onFulfilled(value)}); } + return new myPromise((resolve,reject)=>{ + resolve() + }) } } 复制代码
修改完成之后,我们执行看看
经过观察我们可以发现
p2-resolve-then2已经成功的打印出来了,只是和别人家的promise打印的位置不太对
第二个then的返回值问题
第二个then的onFulfilled的参数是第一个onFuifilled的return值
所以我们修改一下我们执行代码
![](/upload/202007/06/202007061127381118.png)
这里有一个小tips,这里用了并的逻辑运算符,console.log()这个函数返回一个undefined,所以在前面取了非
花开两朵各表一枝,
我们观察发现
别人家的promise的第二个then能够正常的接收到第一个then传递过来的值 咱们家的promis却不能,其实也不奇怪,咱们家的promise在then里面返回的promise中的resolve方法中没有参数!!!
![](/upload/202007/06/202007061127383345.png)
我们按着这个思路,来改改咱们家的promise
class myPromise { constructor(executor) { this.state = "pending"; //内部状态为pending,resolve,reject this.value = null; this.reason = null; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === "pending") { this.state = "fulfilled"; this.value = value; this.onFulfilledCallbacks.forEach((fn) => fn(value)); } }; const reject = (reason) => { if (this.state === "pending") { this.state = "rejected"; this.reason = reason; this.onRejectedCallbacks.forEach((fn) => fn(reason)); } }; try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFulfilled, onRejected) { const promise2 = new myPromise((resolve, reject) => { if (this.state === "fulfilled") { setTimeout(() => { + // 万一onFulfilled方法报错,我们用trycatch捕获一下 + try { + let x = onFulfilled(this.value); + resolve(x) + } catch (error) { + reject(error) + } }) } if (this.state === "rejected") { setTimeout(() => { + try { + let x = onRejected(this.reason); + //这里暂时有点问题,我们先这么写,因为这里比较符合逻辑 + reject(x) + } catch (error) { + reject(error) + } }) } if (this.state === "pending") { this.onFulfilledCallbacks.push(value => { + try { + let x = onFulfilled(value) + resolve(x) + } catch (error) { + reject(error) + } }); this.onRejectedCallbacks.push(reason => { + try { + let x = onRejected(reason) + //这里暂时有点问题,我们先这么写,因为这里比较符合逻辑 + reject(x) + } catch (error) { + reject(error) + } }); } }) return promise2; } } 复制代码
最后来看看结果
观察可以返现,咱们家的promise已经和别人家的promise已经越来越像了(牛头人警告!)
then函数的onRejected的返回会被下一个then函数的onFulfilled方法接受
我们来看看例子
仔细观察我们发现
别人家的promise的then函数链的执行是p1-reject-then1(第一个then的onRejected)=>p1-resolve-then2(第二个then的onFulfilled) 咱们家的promise的then函数链的执行是p2-reject-then1(第一个then的onRejected)=>p2-reject-then2(第二个then的onRejected) 这里的不同是promise的reject不需要传递(这是约定,不要为我为啥)
我画了一个图
![](/upload/202007/06/202007061127387388.png)
所以我们来修改咱们家的promise
class myPromise { constructor(executor) { this.state = "pending"; //内部状态为pending,resolve,reject this.value = null; this.reason = null; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === "pending") { this.state = "fulfilled"; this.value = value; this.onFulfilledCallbacks.forEach((fn) => fn(value)); } }; const reject = (reason) => { if (this.state === "pending") { this.state = "rejected"; this.reason = reason; this.onRejectedCallbacks.forEach((fn) => fn(reason)); } }; try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFulfilled, onRejected) { const promise2 = new myPromise((resolve, reject) => { if (this.state === "fulfilled") { setTimeout(() => { // 万一onFulfilled方法报错,我们用trycatch捕获一下 try { let x = onFulfilled(this.value); resolve(x) } catch (error) { reject(error) } }) } if (this.state === "rejected") { setTimeout(() => { try { let x = onRejected(this.reason); - //这里暂时有点问题,我们先这么写,因为这里比较符合逻辑 - reject(x) + resolve(x) } catch (error) { reject(error) } }) } if (this.state === "pending") { this.onFulfilledCallbacks.push(value => { try { let x = onFulfilled(value) resolve(x) } catch (error) { reject(error) } }); this.onRejectedCallbacks.push(reason => { try { let x = onRejected(reason) - //这里暂时有点问题,我们先这么写,因为这里比较符合逻辑 - reject(x) + reslove(x) } catch (error) { reject(error) } }); } }) return promise2; } } 复制代码
修改完了,我们来看看结果
![](/upload/202007/06/202007061127388961.png)
bingo!!! 咱们家的promise又像了别人家的promise几分
调整一下结构
大体上的 结构已经完成了,接下来我们要调整一下,方便接下来的对比
class myPromise { constructor(executor) { this.state = "pending"; //内部状态为pending,resolve,reject this.value = null; this.reason = null; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === "pending") { this.state = "fulfilled"; this.value = value; this.onFulfilledCallbacks.forEach((fn) => fn(value)); } }; const reject = (reason) => { if (this.state === "pending") { this.state = "rejected"; this.reason = reason; this.onRejectedCallbacks.forEach((fn) => fn(reason)); } }; try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFulfilled, onRejected) { const promise2 = new myPromise((resolve, reject) => { if (this.state === "fulfilled") { setTimeout(() => { // 万一onFulfilled方法报错,我们用trycatch捕获一下 try { let x = onFulfilled(this.value); - reslove(x) + resolvePromise(promise,x,resolve,reject) } catch (error) { reject(error) } }) } if (this.state === "rejected") { setTimeout(() => { try { let x = onRejected(this.reason); - reslove(x) + resolvePromise(promise,x,resolve,reject) } catch (error) { reject(error) } }) } if (this.state === "pending") { this.onFulfilledCallbacks.push(value => { try { let x = onFulfilled(value) - reslove(x) + resolvePromise(promise,x,resolve,reject) } catch (error) { reject(error) } }); this.onRejectedCallbacks.push(reason => { try { let x = onRejected(reason) - reslove(x) + resolvePromise(promise,x,resolve,reject) } catch (error) { reject(error) } }); } }) return promise2; } } + function resolvePromise(promise2,x,resovle,reject) { + resolve(x) + } 复制代码
我们创建了一个函数resolvePromise 专门来处理resolve相关的逻辑,因为这部分高度复用,所以我们把它单独抽离成一个函数,目前这个函数里面还是只执行了resolve(x)
当onFulfilled/onRejected的返回值是一个promise对象时
观察可以发现,
别人家的promise正常的将promise里面的resolve值传递给了第二个then方法 咱们家的promise,像一个铁憨憨一下,把promise实例当一个值返回了
这里咱们要弄懂,promise链式调用,具体的实现逻辑
![](/upload/202007/06/202007061127392017.png)
解析:
一般情况下,我们调用resolve传递的是当前then(onFulfilled,onRejected)的onFulfilled和onRejected的返回 当onFulfilled和onRejected的返回是一个promise实例时,resolve传递的是当前这个实例的then(onFullfilled,onRejected)中的onFullfilled/onRejected的返回
根据我们的理解,来修改咱们家的promise
class myPromise { constructor(executor) { this.state = "pending"; //内部状态为pending,resolve,reject this.value = null; this.reason = null; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === "pending") { this.state = "fulfilled"; this.value = value; this.onFulfilledCallbacks.forEach((fn) => fn(value)); } }; const reject = (reason) => { if (this.state === "pending") { this.state = "rejected"; this.reason = reason; this.onRejectedCallbacks.forEach((fn) => fn(reason)); } }; try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFulfilled, onRejected) { const promise2 = new myPromise((resolve, reject) => { if (this.state === "fulfilled") { setTimeout(() => { // 万一onFulfilled方法报错,我们用trycatch捕获一下 try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }) } if (this.state === "rejected") { setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }) } if (this.state === "pending") { this.onFulfilledCallbacks.push(value => { try { let x = onFulfilled(value) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }); this.onRejectedCallbacks.push(reason => { try { let x = onRejected(reason) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }); } }) return promise2; } } function resolvePromise(promise2, x, resolve, reject) { + if (x instanceof myPromise) { + if (x.state === 'pending') { + x.then((y) => { + resolvePromise(promise2, y, resolve, reject) + }, reject) + } else { + x.then(resolve, reject) + } + } else { resolve(x) + } } 复制代码
修改了之后,我们来看看
![](/upload/202007/06/202007061127393326.png)
观察以后,发现咱们家的promise也越来越标准化了
特殊中的特殊情况
当resolve返回的是一个包含then函数的对象,或者函数时,要执行一次这个then函数
首先我们来看看对比
![](/upload/202007/06/202007061127394732.png)
经过观察我们可以发现,
别人家的promise是成功的返回了,fn1的入参 而咱们家的promise却吧整个对象都返回了 别人家的promise,调用了fn1和fn2,但是只执行了排在前面的fn1,是因为fn1和fn2和resolve/reject一样都有单一执行原则 小问题,如果then里面的fn1/fn2返回的是一个promise对象呢?这个问题仔细想想? 结论就是,我们还要按照promise的标准再一次处理一下
我们按照我们的想法来完善咱们家的promise
class myPromise { constructor(executor) { this.state = "pending"; //内部状态为pending,resolve,reject this.value = null; this.reason = null; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === "pending") { this.state = "fulfilled"; this.value = value; this.onFulfilledCallbacks.forEach((fn) => fn(value)); } }; const reject = (reason) => { if (this.state === "pending") { this.state = "rejected"; this.reason = reason; this.onRejectedCallbacks.forEach((fn) => fn(reason)); } }; try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFulfilled, onRejected) { const promise2 = new myPromise((resolve, reject) => { if (this.state === "fulfilled") { setTimeout(() => { // 万一onFulfilled方法报错,我们用trycatch捕获一下 try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }) } if (this.state === "rejected") { setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }) } if (this.state === "pending") { this.onFulfilledCallbacks.push(value => { try { let x = onFulfilled(value) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }); this.onRejectedCallbacks.push(reason => { try { let x = onRejected(reason) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }); } }) return promise2; } } function resolvePromise(promise2, x, resolve, reject) { if (x instanceof myPromise) { if (x.state === 'pending') { x.then((y) => { resolvePromise(promise2, y, resolve, reject) }, reject) } else { x.then(resolve, reject) } + } else if(x && (typeof x === 'object'|| typeof x === 'function')){ + let called = false; + try { + let then = x.then; + if(typeof then === 'function'){ + then.call(x,(y)=>{ + if(called) return; + called = true; + resolvePromise(promise2,y,resolve,reject); + },(e)=>{ + if(called) return; + called = true; + reject(e) + }) + }else{ + resolve(x) + } + } catch (error) { + if(called) return; + called = true; + reject(error) + } + } else { resolve(x) } } 复制代码
修改完了之后,我们来看看结果
当然返回一个有then方法的函数结果也是一样的
![](/upload/202007/06/202007061127400357.png)
可以看见咱们家的promise,又一次完成进化,现在快成长成一个独当一面的promise了
处理极端情况
then(onFulfilled,onRejected)中的onFulFilled返回的是当前的then()
我们来看看对比
观察可以发现
别人家的promise报错了 咱们家的promise没有反应 咱们家的promise没有反应,是因为它在无限的执行then,陷入了死循环
我们画个图
这是一个正常情况
![](/upload/202007/06/202007061127403561.png)
当2这onFulfilled返回的是上面整个then时,就陷入了自我循环
![](/upload/202007/06/202007061127408786.png)
所以这里,我们阻止一下自我循环
class myPromise { ... } function resolvePromise(promise2, x, resolve, reject) { + if(promise2===x) { + return reject(new TypeError('自我循环')) + } if (x instanceof myPromise) { ... } } 复制代码
当then(onFulfilled,onRejected)中的onFulfilled,onRejected不为function时
这里是约定,所以没有啥理由
我们来加上
then(onFulfilled, onRejected) { + onFulfilled = typeof onFulfilled === 'function'? onFulfilled:y=>y; + onRejected = typeof onRejected === 'function'? onRejected:y=>{throw y;} let promise2 = new myPromise((resolve, reject) => { 复制代码
当一个promise的reslove的参数是一个promise的时候
暂时不知道为什么,有知道的大佬说明一下 这个也是一个约定,我们来看一个例子
![](/upload/202007/06/202007061127410329.png)
观察之后,可以发现,resolve的promise传递是reslove的值,而reject是直接传递promise实例 所以我们来改造咱们家的promise
const resolve = (value) => { + if (value instanceof myPromise) { + return value.then(resolve, reject) + } if (this.state === "pending") { this.state = "fulfilled"; this.value = value; this.onFulfilledCallbacks.forEach((fn) => fn(value)); } }; 复制代码
到这里,咱们家的promise,大概就是这个样子的
class myPromise { constructor(executor) { this.state = "pending"; //内部状态为pending,resolve,reject this.value = null; this.reason = null; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (value instanceof myPromise) { return value.then(resolve, reject) } if (this.state === "pending") { this.state = "fulfilled"; this.value = value; this.onFulfilledCallbacks.forEach((fn) => fn(value)); } }; const reject = (reason) => { if (this.state === "pending") { this.state = "rejected"; this.reason = reason; this.onRejectedCallbacks.forEach((fn) => fn(reason)); } }; try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : y => y; onRejected = typeof onRejected === 'function' ? onRejected : y => { throw y; } const promise2 = new myPromise((resolve, reject) => { if (this.state === "fulfilled") { setTimeout(() => { // 万一onFulfilled方法报错,我们用trycatch捕获一下 try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }) } if (this.state === "rejected") { setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }) } if (this.state === "pending") { this.onFulfilledCallbacks.push(value => { setTimeout(() => { try { let x = onFulfilled(value) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }) }); this.onRejectedCallbacks.push(reason => { setTimeout(() => { try { let x = onRejected(reason) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }) }); } }) return promise2; } } function resolvePromise(promise2, x, resolve, reject) { if (x === promise2) { return new TypeError('自我循环') } if (x instanceof myPromise) { if (x.state === 'pending') { x.then((y) => { resolvePromise(promise2, y, resolve, reject) }, reject) } else { x.then(resolve, reject) } } else if (x && (typeof x === 'object' || typeof x === 'function')) { let called = false; try { let then = x.then; if (typeof then === 'function') { then.call(x, (y) => { if (called) return; called = true; resolvePromise(promise2, y, resolve, reject); }, (e) => { if (called) return; called = true; reject(e) }) } else { resolve(x) } } catch (error) { if (called) return; called = true; reject(error) } } else { resolve(x) } } 复制代码
最后用promises-aplus-tests测试一下我们的promise
npm init npm i promises-aplus-tests -D 复制代码
修改一下package.json
"scripts": { // 后面接你的文件 "test": "promises-aplus-tests ./src/index.js" }, 复制代码
执行
npm run test 复制代码
![](/upload/202007/06/202007061127411979.png)
最后发现有40测试没通过
少年,你还记得一招从天而降的掌法吗?
这里,其他的文章会告诉这是promise的规范,就仿佛回到了小学时代,我懵懵懂懂的问老师问题时,老师告诉我只需要记住就行了。 但是,我拒绝!!!
我们来看一个极端的例子
![](/upload/202007/06/202007061127413415.png)
为什么不一样的呢?
究其根本原因,resolvePromise返回了一个状态为fuifilled的promise
![](/upload/202007/06/202007061127414440.png)
在promise内部的resolvePromise()方法内,直接执行了x.then(reslove,reject)
![](/upload/202007/06/202007061127417565.png)
所以把custom thenable当成了值,错误的返回了
这里怎么处理呢
class myPromise { constructor(executor) { this.state = "pending"; //内部状态为pending,resolve,reject this.value = null; this.reason = null; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (value instanceof myPromise) { return value.then(resolve, reject); } + setTimeout(() => { if (this.state === "pending") { this.state = "fulfilled"; this.value = value; this.onFulfilledCallbacks.forEach((fn) => fn(value)); } + }) }; const reject = (reason) => { + setTimeout(()=>{ if (this.state === "pending") { this.state = "rejected"; this.reason = reason; this.onRejectedCallbacks.forEach((fn) => fn(reason)); } + }) }; try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : y => y; onRejected = typeof onRejected === 'function' ? onRejected : y => { throw y; } const promise2 = new myPromise((resolve, reject) => { if (this.state === "fulfilled") { setTimeout(() => { // 万一onFulfilled方法报错,我们用trycatch捕获一下 try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }) } if (this.state === "rejected") { setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }) } if (this.state === "pending") { this.onFulfilledCallbacks.push(value => { - setTimeout(() => { try { let x = onFulfilled(value) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } - }) }); this.onRejectedCallbacks.push(reason => { - setTimeout(() => { try { let x = onRejected(reason) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } - }) }); } }) return promise2; } } function resolvePromise(promise2, x, resolve, reject) { if (x === promise2) { return reject(new TypeError('自我循环')) } if (x instanceof myPromise) { if (x.state === 'pending') { x.then((y) => { resolvePromise(promise2, y, resolve, reject) }, reject) } else { x.then(resolve, reject) } } else if (x && (typeof x === 'object' || typeof x === 'function')) { let called = false; try { let then = x.then; if (typeof then === 'function') { then.call(x, (y) => { if (called) return; called = true; resolvePromise(promise2, y, resolve, reject); }, (e) => { if (called) return; called = true; reject(e) }) } else { resolve(x) } } catch (error) { if (called) return; called = true; reject(error) } } else { resolve(x) } } 复制代码
我们把所有的resolve/reject都改成异步触发
最后的最后
我们执行 执行
npm run test 复制代码
![](/upload/202007/06/202007061127418581.png)
终于通过了全部的测试用例了
最终代码
class myPromise { constructor(executor) { this.state = "pending"; //内部状态为pending,resolve,reject this.value = null; this.reason = null; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (value instanceof myPromise) { return value.then(resolve, reject); } setTimeout(() => { if (this.state === "pending") { this.state = "fulfilled"; this.value = value; this.onFulfilledCallbacks.forEach((fn) => fn(value)); } }); }; const reject = (reason) => { setTimeout(() => { if (this.state === "pending") { this.state = "rejected"; this.reason = reason; this.onRejectedCallbacks.forEach((fn) => fn(reason)); } }); }; try { executor(resolve, reject); } catch (e) { reject(e); } } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (y) => y; onRejected = typeof onRejected === "function" ? onRejected : (y) => { throw y; }; const promise2 = new myPromise((resolve, reject) => { if (this.state === "fulfilled") { setTimeout(() => { // 万一onFulfilled方法报错,我们用trycatch捕获一下 try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }); } if (this.state === "rejected") { setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }); } if (this.state === "pending") { this.onFulfilledCallbacks.push((value) => { try { let x = onFulfilled(value); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }); this.onRejectedCallbacks.push((reason) => { try { let x = onRejected(reason); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }); } }); return promise2; } } function resolvePromise(promise2, x, resolve, reject) { if (x === promise2) { return reject(new TypeError("自我循环")); } if (x instanceof myPromise) { if (x.state === "pending") { x.then((y) => { resolvePromise(promise2, y, resolve, reject); }, reject); } else { x.then(resolve, reject); } } else if (x && (typeof x === "object" || typeof x === "function")) { let called = false; try { let then = x.then; if (typeof then === "function") { then.call( x, (y) => { if (called) return; called = true; resolvePromise(promise2, y, resolve, reject); }, (e) => { if (called) return; called = true; reject(e); } ); } else { resolve(x); } } catch (error) { if (called) return; called = true; reject(error); } } else { resolve(x); } } myPromise.deferred = function () { let defer = {}; defer.promise = new myPromise((resolve, reject) => { defer.resolve = resolve; defer.reject = reject; }); return defer; }; module.exports = myPromise; 复制代码
本文使用 mdnice 排版
这篇关于你能白瞟到的最“善解人意”的Promise实现的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-06-26结对编程到底难不难?答案在这里
- 2024-06-19《2023版Java工程师》课程升级公告
- 2024-06-15matplotlib作图不显示3D图,怎么办?
- 2024-06-1503-Loki 日志监控
- 2024-06-1504-让LLM理解知识 -Prompt
- 2024-06-05做软件测试需要懂代码吗?
- 2024-06-0514-ShardingSphere的分布式主键实现
- 2024-06-03为什么以及如何要进行架构设计权衡?
- 2024-05-31全网首发第二弹!软考2024年5月《软件设计师》真题+解析+答案!(11-20题)
- 2024-05-31全网首发!软考2024年5月《软件设计师》真题+解析+答案!(21-30题)