安庆大理运城常德铜陵江西
投稿投诉
江西南阳
嘉兴昆明
铜陵滨州
广东西昌
常德梅州
兰州阳江
运城金华
广西萍乡
大理重庆
诸暨泉州
安庆南充
武汉辽宁

手撕Promise之从0开始实现完整的Promise对象

12月28日 尘世客投稿
  1。定义对象分析经典Promise对象
  经典的Promise对象结构代码如下:
  1。查看空Promise对象的结构和输出结果:varpnewPromise(function(resolve,reject){console。log(resolve,reject)})console。log(p)
  输出结果如下:(){〔nativecode〕}(){〔nativecode〕}Promise〔〔Prototype〕〕:Promise〔〔PromiseState〕〕:pending〔〔PromiseResult〕〕:undefined
  2。查看fulfilled状态下的Promise对象:varpnewPromise(function(resolve,reject){resolve(已完成)})console。log(p)
  输出结果如下:Promise{fulfilled:已完成}〔〔Prototype〕〕:Promise〔〔PromiseState〕〕:fulfilled〔〔PromiseResult〕〕:已完成
  3。查看rejected状态下的Promise对象:varpnewPromise(function(resolve,reject){reject(已拒绝)})console。log(p)
  输出结果如下:Promise{rejected:已拒绝}〔〔Prototype〕〕:Promise〔〔PromiseState〕〕:rejected〔〔PromiseResult〕〕:已拒绝Uncaught(inpromise)已拒绝Promise对象的基本结构定义
  根据Promise对象的特点分析,Promise存在状态属性和Promise的值的属性。初始化Promise时需要传入一个回调函数来进行对象的基本设置,回调函数具备两个参数resolve和reject,两个参数均为函数。所以初始化代码如下:functionMyPromise(fn){promise的初始状态为pending,可变成fulfilled或rejected其中之一this。promiseStatependingthis。promiseValueundefinedvarresolvefunction(){}varrejectfunction(){}if(fn){fn(resolve,reject)}else{throw(InitError,PleaseuseafunctiontoinitMyPromise!)}}
  根据对象特性,初始化Promise时的回调函数是同步执行的,所以此时的fn直接调用即可。
  在调用resolve和reject时,需要将Promise对象的状态设置为对应的fulfilled和rejected,其中需要传入Promise当前的结果,所以此时应该将resolve和reject修改为如下结构。保存上下文对象varthisthisvarresolvefunction(value){if(this。promiseStatepending){this。promiseStatefulfilledthis。promiseValuevalue}}varrejectfunction(value){if(this。promiseStatepending){this。promiseStaterejectedthis。promiseValuevalue}}
  定义完内部结构之后需要思考Promise在状态变更为fulfilled以及状态变更为rejected时对应的then和catch会相应执行,所以需要将对象的两个函数初始化:MyPromise。prototype。thenfunction(callback){}MyPromise。prototype。catchfunction(callback){}
  那么初始对象的结构应该整体是这样的:functionMyPromise(fn){promise的初始状态为pending,可变成fulfilled或rejected其中之一this。promiseStatependingthis。promiseValueundefinedvarthisthisvarresolvefunction(value){if(this。promiseStatepending){this。promiseStatefulfilledthis。promiseValuevalue}}varrejectfunction(value){if(this。promiseStatepending){this。promiseStaterejectedthis。promiseValuevalue}}if(fn){fn(resolve,reject)}else{throw(InitError,PleaseuseafunctiontoinitMyPromise!)}}MyPromise。prototype。thenfunction(callback){}MyPromise。prototype。catchfunction(callback){}实现then的调用
  在实现了初始结构之后,我们需要使用MyPromise按照Promise的方式进行编程,来实现他的流程控制部分了。首先我们需要让then跑起来。
  定义调用代码:varpnewMyPromise(function(resolve,reject){resolve(123)})console。log(p)p。then(function(res){console。log(res)})
  此时执行代码时控制台会输出如下内容:MyPromisepromiseState:fulfilledpromiseValue:123〔〔Prototype〕〕:Object
  我们发现我们定义的Promise对象状态已经变更但是then中的回调函数没有执行。
  接下来我们实现then的触发:在MyPromise中改造该部分代码如下定义then的回调函数this。thenCallbackundefinedvarresolvefunction(value){if(this。promiseStatepending){this。promiseStatefulfilledthis。promiseValuevalue异步的执行then函数中注册的回调函数setTimeout(function(){if(this。thenCallback){this。thenCallback(value)}})}}在then中编写如下代码MyPromise。prototype。thenfunction(callback){then第一次执行时注册回调函数到当前的Promise对象this。thenCallbackfunction(value){callback(value)}}
  在两处改造完成之后访问网页会发现控制台上可以输出then函数中的回调执行的结果并且该结果的参数就是resolve传入的值。MyPromise{promiseState:fulfilled,promiseValue:123,thenCallback:undefined}promise。html:51123
  当前代码效果如下:functionMyPromise(fn){promise的初始状态为pending,可变成fulfilled或rejected其中之一this。promiseStatependingthis。promiseValueundefinedvarthisthis定义then的回调函数this。thenCallbackundefinedvarresolvefunction(value){if(this。promiseStatepending){this。promiseStatefulfilledthis。promiseValuevalue异步的执行then函数中注册的回调函数setTimeout(function(){if(this。thenCallback){this。thenCallback(value)}})}}varrejectfunction(value){if(this。promiseStatepending){this。promiseStaterejectedthis。promiseValuevalue}}if(fn){fn(resolve,reject)}else{throw(InitError,PleaseuseafunctiontoinitMyPromise!)}}MyPromise。prototype。thenfunction(callback){then第一次执行时注册回调函数到当前的Promise对象this。thenCallbackfunction(value){callback(value)}}MyPromise。prototype。catchfunction(callback){}varpnewMyPromise(function(resolve,reject){resolve(123)})console。log(p)p。then(function(res){console。log(res)})实现then的异步链式调用
  通过上面的编程已经可以实现then自动触发,但是当前我们如果将代码变成如下效果时只有一个then能执行。而且控制台会报错varpnewMyPromise(function(resolve,reject){resolve(123)})console。log(p)p。then(function(res){console。log(res)})。then(function(res){console。log(res)})。then(function(res){console。log(res)})
  控制台信息如下:MyPromise{promiseState:fulfilled,promiseValue:123,thenCallback:undefined}promise。html:52UncaughtTypeError:Cannotreadpropertiesofundefined(readingthen)atpromise。html:52(anonymous)promise。html:52promise。html:51123
  针对该情况,我们需要对Promise的流程控制代码做进一步的加强以实现链式调用,并且在链式调用的过程中将每次的结果顺利的向下传递。resolve部分代码实现varresolvefunction(value){if(this。promiseStatepending){this。promiseValuevaluethis。promiseStatefulfilled当传入的类型是Promise对象时if(valueinstanceofMyPromise){value。then(function(res){this。thenCallback(res)})}else{当传入的数据类型是普通变量时setTimeout(function(){if(this。thenCallback){this。thenCallback(value)}})}}}then函数代码实现MyPromise。prototype。thenfunction(callback){varthisthisreturnnewMyPromise(function(resolve,reject){this。thenCallbackfunction(value){varcallbackRescallback(value)resolve(callbackRes)}})}
  将then代码修改为如下之后我们将调用代码更改如下varpnewMyPromise(function(resolve){resolve(newMyPromise(function(resolve1){resolve1(aaa)}))})p。then(function(res){console。log(res)return123})。then(function(res){console。log(res)returnnewMyPromise(function(resolve){setTimeout(function(){resolve(Promise)},2000)})})。then(function(res){console。log(res)})console。log(p)
  会惊喜的发现MyPromise对象可以正常的工作了并且还可以实现何时调用resolve何时执行then的操作MyPromise{promiseValue:MyPromise,promiseState:fulfilled,catchCallback:undefined,thenCallback:}test。html:57aaatest。html:60123test。html:67Promise
  当前状态的代码如下functionMyPromise(fn){varthisthisthis。promiseValueundefinedthis。promiseStatependingthis。thenCallbackundefinedthis。catchCallbackundefinedvarresolvefunction(value){if(this。promiseStatepending){this。promiseValuevaluethis。promiseStatefulfilledif(valueinstanceofMyPromise){value。then(function(res){this。thenCallback(res)})}else{setTimeout(function(){if(this。thenCallback){this。thenCallback(value)}})}}}varrejectfunction(err){}if(fn){fn(resolve,reject)}else{throw(InitError,PleaseuseafunctiontoinitMyPromise!)}}MyPromise。prototype。thenfunction(callback){varthisthisreturnnewMyPromise(function(resolve,reject){this。thenCallbackfunction(value){varcallbackRescallback(value)resolve(callbackRes)}})}varpnewMyPromise(function(resolve){resolve(newMyPromise(function(resolve1){resolve1(aaa)}))})实现catch的流程处理
  当Promise的对象触发reject操作的时候他的状态会变更为rejected,此时会触发catch函数,并且catch函数触发后流程结束。
  首先仿照then的方式在MyPromise对象中定义好初始通知函数定义catch的回调函数this。catchCallbackundefinedvarrejectfunction(err){if(this。promiseStatepending){this。promiseValueerrthis。promiseStaterejectedsetTimeout(function(){if(this。catchCallback){this。catchCallback(err)}})}}
  然后在catch函数中做如下处理MyPromise。prototype。catchfunction(callback){varthisthisreturnnewMyPromise(function(resolve,reject){this。catchCallbackfunction(errValue){varcallbackRescallback(errValue)resolve(callbackRes)}})}
  调用代码如下varpnewMyPromise(function(resolve,reject){reject(err)})p。catch(function(err){console。log(err)})
  当运行此时代码时我们会发现我们的Promise对象在控制台上可以直接触发catch的回调执行并输出对应的结果MyPromise{promiseValue:err,promiseState:rejected,thenCallback:undefined,catchCallback:}test。html:73err实现跨对象执行catch
  在上面的案例中已经可以执行MyPromise的catch函数了,但是如果将调用代码改为如下行为会发现catch函数不会执行varpnewMyPromise(function(resolve,reject){reject(123)})console。log(p)p。then(function(res){console。log(res)})。catch(function(err){console。log(err)})
  这是因为按照我们编写的代码流程Promise对象会自动变更状态为rejected并且catch的回调函数无法注册,所以Promise的流程就断了。这个时候需要追加判断代码让Promise在rejected时如果没有catchCallback再去检测是否存在thenCallbackvarrejectfunction(err){if(this。promiseStatepending){this。promiseValueerrthis。promiseStaterejectedsetTimeout(function(){if(this。catchCallback){this。catchCallback(err)}elseif(this。thenCallback){this。thenCallback(err)}else{throw(thisPromisewasreject,butcannotfoundcatch!)}})}}
  该步骤操作完毕之后我们需要将then函数中的逻辑再次更改为如下MyPromise。prototype。thenfunction(callback){varthisthis实现链式调用并且每个节点的状态是未知的所以每次都需要返回一个新的Proimse对象returnnewMyPromise(function(resolve,reject){then第一次执行时注册回调函数到当前的Promise对象this。thenCallbackfunction(value){判断如果进入该回调时Promise的状态为rejected那么就直接触发后续Promise的catchCallback直到找到catchif(this。promiseStaterejected){reject(value)}else{varcallbackRescallback(value)resolve(callbackRes)}}})}
  修改如下之后调用代码改造为varpnewMyPromise(function(resolve,reject){reject(err)})p。then(function(res){console。log(res)return111})。then(function(res){console。log(res)return111})。then(function(res){console。log(res)return111})。catch(function(err){console。log(err)})console。log(p)
  输出结果为MyPromise{promiseValue:err,promiseState:rejected,catchCallback:undefined,thenCallback:}test。html:91err实现链式调用的中断
  本文仅介绍通过返回Promise对象来中断链式调用,首先在Promise的原型对象上增加reject方法如下:MyPromise。rejectfunction(value){returnnewMyPromise(function(resolve,reject){reject(value)})}
  然后初始化如下调用代码varpnewMyPromise(function(resolve,reject){resolve(123)})console。log(p)p。then(function(res){console。log(then1执行)return456})。then(function(res){console。log(then2执行)returnMyPromise。reject(中断了)})。then(function(res){console。log(then3执行)return789})。then(function(res){console。log(then4执行)return666})。catch(function(err){console。log(catch执行)console。log(err)})
  最后修改调试代码中的thenMyPromise。prototype。thenfunction(callback){varthisthisreturnnewMyPromise(function(resolve,reject){this。thenCallbackfunction(value){if(this。promiseStaterejected){reject(value)}else{varcallbackRescallback(value)if(callbackResinstanceofMyPromise){if(callbackRes。promiseStaterejected){callbackRes。catch(function(errValue){reject(errValue)})}}else{resolve(callbackRes)}}}})}
  根据代码分析处理逻辑,然后查看运行结果:MyPromise{promiseState:fulfilled,promiseValue:123,thenCallback:undefined,catchCallback:undefined}promise。html:100then1执行promise。html:103then2执行promise。html:112catch执行promise。html:113中断了
  最后我们发现在返回Promise。reject()之后then的链式调用便中断了。实现all和race
  1。Promise。all的实现MyPromise。allfunction(promiseArr){varresArr〔〕varerrValueundefinedvarisRejectedfalsereturnnewMyPromise(function(resolve,reject){for(vari0;ipromiseArr。i){(function(i){promiseArr〔i〕。then(function(res){resArr〔i〕resletrpromiseArr。every(item{returnitem。promiseStatefulfilled})if(r){resolve(resArr)}})。catch(function(err){isRejectedtrueerrValueerrreject(err)})})(i)if(isRejected){break}}})}
  1。Promise。race的实现MyPromise。racefunction(promiseArr){varendfalsereturnnewMyPromise(function(resolve,reject){for(vari0;ipromiseArr。i){(function(i){promiseArr〔i〕。then(function(res){if(endfalse){endtrueresolve(res)}})。catch(function(err){if(endfalse){endtruereject(err)}})})(i)}})}实现generator的调用
  执行器代码如下:fn:Generator函数对象functiongeneratorFunctionRunner(fn){定义分步对象letgeneratorfn()执行到第一个yieldletstepgenerator。next()定义递归函数functionloop(stepArg,generator){获取本次的yield右侧的结果letvaluestepArg。value判断结果是不是Promise对象if(valueinstanceofMyPromisevalueinstanceofPromise){如果是Promise对象就在then函数的回调中获取本次程序结果并且等待回调执行的时候进入下一次递归value。then(function(promiseValue){if(stepArg。donefalse){loop(generator。next(promiseValue),generator)}})}else{判断程序没有执行完就将本次的结果传入下一步进入下一次递归if(stepArg。donefalse){loop(generator。next(stepArg。value),generator)}}}执行动态调用loop(step,generator)}
  调用代码如下:functiontest(){letres1yieldnewMyPromise(function(resolve){setTimeout(function(){resolve(第一秒)},1000)})console。log(res1)letres2yieldnewMyPromise(function(resolve){setTimeout(function(){resolve(第二秒)},1000)})console。log(res2)letres3yieldnewMyPromise(function(resolve){setTimeout(function(){resolve(第三秒)},1000)})console。log(res3)}generatorFunctionRunner(test)总结
  通过简单的代码片段我们便可以快速的实现一个微型的Promise对象,实现手写代码封装Promise对象虽然对工作没有太大的帮助,但是如果可以根据分析Promise的特性,通过JS原始的异步流程控制方式,来仿真成功Promise对象的内部逻辑,就代表你的JS编程水平已经脱离了普通业务开发的程序员的水平了,希望本文的思路可以给您提供帮助,最后附上源代码。源代码functionMyPromise(fn){varthisthisthis。promiseValueundefinedthis。promiseStatependingthis。thenCallbackundefinedthis。catchCallbackundefinedvarresolvefunction(value){if(this。promiseStatepending){this。promiseValuevaluethis。promiseStatefulfilledif(valueinstanceofMyPromise){if(this。thenCallback){value。then(function(res){this。thenCallback(res)})}}else{setTimeout(function(){if(this。thenCallback){this。thenCallback(value)}})}}}varrejectfunction(err){if(this。promiseStatepending){this。promiseValueerrthis。promiseStaterejectedsetTimeout(function(){if(this。catchCallback){this。catchCallback(err)}elseif(this。thenCallback){this。thenCallback(err)}else{throw(thisPromisewasreject,butcannotfoundcatch!)}})}}if(fn){fn(resolve,reject)}else{throw(InitError,PleaseuseafunctiontoinitMyPromise!)}}MyPromise。prototype。thenfunction(callback){varthisthisreturnnewMyPromise(function(resolve,reject){this。thenCallbackfunction(value){if(this。promiseStaterejected){reject(value)}else{varcallbackRescallback(value)if(callbackResinstanceofMyPromise){if(callbackRes。promiseStaterejected){callbackRes。catch(function(errValue){reject(errValue)})}}else{resolve(callbackRes)}}}})}MyPromise。prototype。catchfunction(callback){varthisthisreturnnewMyPromise(function(resolve,reject){this。catchCallbackfunction(errValue){varcallbackRescallback(errValue)resolve(callbackRes)}})}MyPromise。rejectfunction(value){returnnewMyPromise(function(resolve,reject){reject(value)})}MyPromise。resolvefunction(value){returnnewMyPromise(function(resolve){resolve(value)})}MyPromise。allfunction(promiseArr){varresArr〔〕varerrValueundefinedvarisRejectedfalsereturnnewMyPromise(function(resolve,reject){for(vari0;ipromiseArr。i){(function(i){promiseArr〔i〕。then(function(res){resArr〔i〕resletrpromiseArr。every(item{returnitem。promiseStatefulfilled})if(r){resolve(resArr)}})。catch(function(err){isRejectedtrueerrValueerrreject(err)})})(i)if(isRejected){break}}})}MyPromise。racefunction(promiseArr){varendfalsereturnnewMyPromise(function(resolve,reject){for(vari0;ipromiseArr。i){(function(i){promiseArr〔i〕。then(function(res){if(endfalse){endtrueresolve(res)}})。catch(function(err){if(endfalse){endtruereject(err)}})})(i)}})}
投诉 评论 转载

年轻群体只能通过游戏产品了解国风?近些年来,年轻群体对于国风传统文化的认同感在不断增加,越来越多的年轻人开始通过各种渠道了解优秀传统文化。与此同时,各种节目及产品也在传承国风文化的基础上不断推陈出新,相继出现了……2天上涨309个点!人民币再度升值,你手里的钱更值钱了吗人民币对美元,又开始掉头了!12月初一举收复7。0关口后,人民币好像就停下了上涨的脚步,基本上在6。94到7。0之间波动,而这两天,人民币再度开启升值模式2天涨了309个……索尼推出世界上最小的WUXGA3LCD激光投影机日本电子巨头索尼公司宣布了两款新型超紧凑型激光投影机。VPLPHZ61和VPLPHZ51被誉为世界上最小的WUXGA3LCD激光投影机,将卓越的操作能力与高亮度和灵活的安装相结……财政部决定发行2022年特别国债,面值7500亿元财政部发布通知,为筹集财政资金,支持国民经济和社会事业发展,财政部决定发行2022年特别国债。根据通知,2022年特别国债在全国银行间债券市场面向境内有关银行定向发行,人……推荐一本沟通的书翻阅2022推荐一本好书《非暴力沟通》很值得大家去看一看,书里特别经典的几句话记在下面非暴力沟通指导我们转变谈话和聆听的方式。我们不再条件反射式地反应,而是去……乐视网辟谣并未遭贾跃亭起诉,不靠甄嬛传养老(乐视创始人)贾跃亭因借款纠纷起诉乐视的消息近日内持续发酵,引发热议。11月7日晚间,乐视网旗下乐视视频官方回应称,事件中的乐视控股、乐视移动等公司与乐视网和乐融致新已没有实质……中国版以太坊,合规公链草田链的建设背景与思路分享主持人:亲爱的各位朋友,不管你在世界何处,我们都因为web3而相聚于理想村网上社区,更欢迎各位抵达真实的大理,在苍山洱海之间感受风花雪月之美。现在有请草田链发起人,易小伟……手撕Promise之从0开始实现完整的Promise对象1。定义对象分析经典Promise对象经典的Promise对象结构代码如下:1。查看空Promise对象的结构和输出结果:varpnewPromise(functi……李少莉事件最新消息风波过后低调重返工作岗位,装扮很朴素李少莉事件最新消息,风波过后低调重返工作岗位李少莉因为在发布会上的美艳穿搭扬名四海,她戴的昂贵的耳钉、丝巾让她受到了四面八方的质疑,再加上她在发布会上发言的时候指读发言稿……焦山行宫西出大同三十里到云冈石窟,再往西行三十里到焦山。焦山乃小山包,周匝也就四五里,但形状奇特,如古代车轮横陈于武州川北岸。过桥依山势叠次而上,遇有庙、塔和石窟。庙是泰山庙、河神庙和……一代传奇疤面疤面,是马赛马拉最受欢迎的一头雄狮,也是保护区最吸引游客的景点。疤面的绰号来源于2012年的一次战斗。当时疤面在同其他雄狮战斗中被打伤了眼睛,因此而得名。它独特的脸部特征,也成……实盘周记20221119,今年收益19这周中概股继续大反弹,中概股这波下跌开始于2021年2月,至今已快2年了。这轮下跌可谓一泄千里,几乎没有什么像样的反弹。以致于很多人都认为中国互联网要完蛋了、要被收编了,等等鬼……
光量子芯片不再死磕光刻机,或实现弯道超车新年必备毛衣,EMZ鄂尔多斯带你遇见萌兔,一路兔飞猛进三镇输球佩德罗心有不甘场地条件给对手反击机会遗憾自身犯了错治ED,盲目补肾,导致多年不愈,该怎么补救?深交所表态吸引中长期资金入市中金所减半收费,对股市有什么影响800万澳元墨尔本杯22匹参赛马,19匹为联合马主所有前蚂蚁集团高管为亚洲金融科技基金筹集3亿美元她是陈道明的女儿,36岁成真正的人生赢家,堪称励志星二代去巴基斯坦旅游少女热情欢迎中国人真想娶一个回家强台风梅花再次登陆浙江普陀山,这次能续写转向绕道神话吗?意志力成为高手的底层能力云南普洱山头茶凤凰窝

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找七猫云易事利