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。length;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。length;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。length;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。length;i){(function(i){promiseArr〔i〕。then(function(res){if(endfalse){endtrueresolve(res)}})。catch(function(err){if(endfalse){endtruereject(err)}})})(i)}})}