当前位置: 首页 > Web前端 > HTML5

从零手写一步步实现PromiseA+标准的所有方法

时间:2023-04-05 22:47:28 HTML5

~Promise本文全部实现Promise的所有方法,代码全部测试可运行,写于2019年11月17日,GitHub仓库还有自己实现的webpack、mini-react、redux、react-redux、websocket、Electron跨平台桌面、React-native移动端开源项目等仓库地址:https://github.com/JinJieTan评论承诺:newPromise中的构造函数同步执行,然后回调函数以微任务的形式执行。调用resolve和reject后,状态不能再改变,传递的值也是每次.then后返回的promise。承诺可以嵌套。逻辑:1.Promise被new调用2.每次失败或者成功都需要指定一个回调函数,可以传一个值3.Promise有一个.then方法。上面的代码有问题。状态改变应该是异步的,.then应该是一个microtaskForm执行异步改变状态,支持三种状态版本:writingthinking状态只能通过Pending改变,异步改变状态只能改变一次,异步执行。然后支持链式调用写到这里,需要暂停一下,梳理思路。万事开头难。其实写一个Promise是一件很简单的事情。看完上面两段代码,再把这三点理解透彻,往下看。Promise的构造函数是同步执行的。resolve和reject的调用是同步调用异步执行的。比如resolve()是同步调用resolve函数,但是resolve函数里面的代码是异步的。---即异步改变状态,异步执行。thennewPromise((resolve,reject)=>{console.log('这里是同步执行')resolve('resolve函数里面是异步执行')}).then(()=>{console.log('这里等待resolve函数内部的异步执行,等状态改变后再执行')})把上面的例子和两句话看透,然后你可以往下看,其实下面也是都是重复性或者细节性的工作支持。那么链式调用想要支持链式操作,其实很简单。首先,在存储回调时,需要使用数组self.onFulfilledCallbacks=[];self.onRejectedCallbacks=[]当然执行回调的时候也要改成遍历回调数组来执行回调函数。最后,then方法也应该改变。你只需要在最后一行添加一个returnthis。这其实和jQuery链式运算的原理是一致的。每次方法调用都返回自己的实例,后面的方法也是该实例的方法,所以可以继续执行。写思路1.将所有成功和失败的回调函数存储在数组中,遍历执行2.为了支持链式调用,只返回这个实例对象3.每次状态改变时清除所有队列回调4.当前方法Only支持同步回调,下面会增加异步异步链调用的支持。这里好像是最难的点,但是应用层的难点可以通过增加一个中间层来解决。加2真的不行---来自中国的未知码农看下面的Node.js代码:在上面的场景中,我们读取1.txt并打印1.txt的内容,然后读取2.txt并打印2.txt的内容,然后读取3.txt并打印3.txt的内容,读取文件都是异步操作,所以都是返回一个promise。上一节我们实现的promise在执行异步操作后可以执行后续的回调,但是本节的回调读取文件内容操作不是同步的,而是异步的,所以读取1.txt后,执行f1、f2、f3时在onFulfilledCallbacks被回调时,异步操作还没有完成,所以我们想得到这样的输出:thisis1.txtthisis2.txtthisis3.txt但实际上它会输出thisis1.txtthisis1。txt这是1.txt上面遇到的问题有点像面试题,测试收尾的一个循环。看看打印输出,你应该有印象了。支持异步链式调用。每次.then返回一个新的承诺。这个新的承诺有自己对应的成功和失败回调(相当于中间层)。另外,每次状态发生变化时,都会清空当前promise对应的回调队列。修改.then方法.then会在链式调用中执行多次。下面是本文的重点思想分析:首先,判断Promise的当前状态。如果状态没有变化,则将它们全部加入队列并调用resolve函数,同时清空队列中的所有Promise。不同的是,bridgePromise是一个用于桥接(作为中间层)的Promise。这里有一个例子来详细解释MyPromise.prototype.then=function(onFulfilled,onRejected){constself=this;让桥梁承诺;//防止使用后者不传递成功或失败回调函数,所以成功或失败回调给默认回调函数onFulfilled=typeofonFulfilled==="function"?onFulfilled:值=>值;onRejected=typeofonRejected===“功能”?onRejected:错误=>{抛出错误};if(self.status===FULFILLED){returnbridgePromise=newMyPromise((resolve,reject)=>{setTimeout(()=>{try{letx=onFulfilled(self.value);resolvePromise(bridgePromise,x,解决,拒绝);}catch(e){拒绝(e);}});})}if(self.status===REJECTED){returnbridgePromise=newMyPromise((resolve,reject)=>{setTimeout(()=>{try{letx=onRejected(self.error);resolvePromise(bridgePromise,x,resolve,reject);}catch(e){reject(e);}});});}if(self.status===PENDING){returnbridgePromise=newMyPromise((resolve,reject)=>{self.onFulfilledCallbacks.push((value)=>{try{letx=onFulfilled(value);resolvePromise(bridgePromise,x,resolve,reject);}catch(e){reject(e);}});self.onRejectedCallbacks.push((error)=>{try{letx=onRejected(error);resolvePromise(bridgePromise,x,决心,拒绝克拉);}抓住(e){拒绝(e);}});});}}这个例子里面是异步代码,但是Promise可以有序的执行我们看一下bridgePromise的源码:代码很简单递归调用直到返回不是Promise,然后调用resolve清除队列,并将返回值存储在self属性中,提供给下一个任务在这里使用。遵守PromiseA+规范,只需修改resolvePromise函数functionresolvePromise(bridgepromise,x,resolve,reject){//2.3.1规范,避免循环引用if(bridgepromise===x){returnreject(newTypeError('循环引用'));}让叫=false;//这个判断分支其实可以删掉,改用下面的分支,因为promise也是一个thenable对象if(xinstanceofMyPromise){if(x.status===PENDING){x.then(y=>{resolvePromise(bridgepromise,y,resolve,reject);},error=>{reject(error);});}else{x.then(解决,拒绝);}//2.3。3规范,如果x是对象或函数}elseif(x!=null&&((typeofx==='object')||(typeofx==='function'))){try{//是否itisthenableobject(object/functionwiththenmethod)//2.3.3.1assignthentox.thenletthen=x.then;if(typeofthen==='function'){//2.3.3.3ifthenis调用then函数的函数,以x为this,第一个参数为resolvePromise,第二个参数为rejectPromisethen.call(x,y=>{if(called)return;called=true;resolvePromise(bridgepromise,y,resolve,reject);},error=>{if(called)return;called=true;reject(error);})}else{//2.3.3.4如果then不是函数,则以x为值实现promiseresolve(x);}}catch(e){//2.3.3.2如果在取x.then的值时抛出异常,则以这个异常为理由拒绝promise。如果(称为)返回;称为=真;拒绝(e);}}else{解决(x);}}implementall,race,resolve,rejectmethodsofes6promiseallmethods:race方法resolve,reject方法~快速定义一个Promise在成功或失败状态下实现promisify方法~实现catch方法~其实并没有通过第一个参数。then方法的语法糖就在这里,一个Promise,实现了所有符合A+规范的方法。网上的实现方法有很多,各不相同,本文实现的比较简单明了。希望能帮助大家更清楚的了解Promise。后续会针对以下内容专门出系列文章~欢迎关注本书公众号:前端巅峰1.从零开始写一个React2。从头开始写一个webpack3。从头开始实现websocket4。从头实现一个vue5。让react和vue优雅的一起开发。这个公众号讲究技术方向。原生JavaScript