您好!欢迎来到爱源码

爱源码

热门搜索: 抖音快手短视频下载   

手写承诺 [源码交易平台]

  • 时间:2022-09-03 00:37 编辑: 来源: 阅读:302
  • 扫一扫,手机访问
摘要:手写承诺 [源码交易平台]
前言现在是2020年。大家肯定都在用Promise,但是估计很多人对它的原理还是一知半解的。今天我们来实现一个符合PromiseA+规范的承诺。 在简单版本中,我们都知道如何调用Promise,有两个参数,new Promise(执行人)和executor,resolve和reject。 所以现在我们的代码是这样的:class promise { constructor(executor){ const resolve =()= >;{ } const reject =()= & gt;{} Executor (resolve,rejcet)}} Promise有三种内部状态,即待定、已履行和已拒绝。最初,它处于待定状态,在调用resolve后变为已履行,在调用reject后变为已拒绝。 完成时调用注册成功的回调,拒绝时调用注册失败的回调。 // Promise内部状态const status = {pending:' pending ',fufilled:' fufilled ',rejected:' rejected'}类Promise { constructor(executor){ this . status = status . pending;this.value = undefinedthis.reason = undefined的值;//失败值constra solve =(val)= >:{ if(this . STATUS = = STATUS。待定){ this.status = STATUS。填充的;this.value = val} } const reject =(原因)= & gt{ if (this.status == STATUS。待定){ this.status = STATUS。被拒;this.reason = reason} }尝试{ executor(resolve,reject);} catch(e){//go to fail logic reject(e)} } then(实现时,拒绝时){if (this。状态= =状态。fufilled){ on fulled(这。值);} if (this.status == STATUS。拒绝){ onRejected(this . reason);}}}现在我们的承诺已经初步实现了,但是还有很多问题。一个承诺可以重复调用then方法,这意味着可以注册多个回调,所以我们需要一个队列来保存这些回调。 同时,我们也没有解决挂起状态下的then方法。当promise处于挂起状态时,那么方法应该将回调放入队列中,而不是直接运行它。 所以改进后的代码如下 const STATUS = { PENDING: 'PENDING ',FUFILLED: 'FUFILLED ',REJECTED:' REJECTED ' } class Promise { constructor(executor){ this . STATUS = STATUS。待定;this.value = undefinedthis.reason = undefined的值;//失败的值+this . onresolvedcallbacks =[];//+this.onRejectedCallbacks = []存储成功的回调;//constra solve =(val)= >存储失败回调的位置;{ if (this.status == STATUS。待定){ this.status = STATUS。填充的;this.value = val//调用成功队列中的回调+this . onresolvedcallbacks . foreach(fn = >;fn());} } const reject =(原因)= & gt{ if (this.status == STATUS。待定){ this.status = STATUS。被拒;this.reason = reason//调用回调+this . onrejectedcallbacks . foreach(fn = >;fn());} }尝试{ executor(resolve,reject);} catch(e){//go to fail logic reject(e)} } then(实现时,拒绝时){if (this。状态= =状态。fufilled){ on fulled(这。值);} if (this.status === STATUS。拒绝){ onRejected(this . reason);}+ if (this.status === STATUS。PENDING){+this . onresolvedcallbacks . push(()= & gt;{ // todo..+on fulfilled(this . value);+})+this . onrejectedcallbacks . push(()= & gt;{ // todo..+on rejected(this . reason);+})+}+}这个简单的承诺已经实现了80%的功能,但是还有一个问题。Promise可以在chain中调用,即promise.then()。然后() 所以我们必须在then方法中返回一个新的承诺。 Const status = {pending:' pending ',fufilled:' fufilled ',rejected:' rejected ' } class promise {//以上逻辑省略...然后(on completed,on rejected){//swt ich scope+let promise 2 = new promise((resolve,reject)= >;{+ if (this.status === STATUS。FUFILLED) {+ //到....+try {+let x = on fulfilled(this . value);+resolve(x);+} catch(e){+reject(e);+ }+ }+ if (this.status === STATUS。拒绝){+try {+let x = on REJECTED(this . reason);+resolve(x);+} catch(e){+reject(e);+ }+ }+ if (this.status === STATUS。PENDING){+this . onresolvedcallbacks . push(()= & gt;{ // todo..+try {+let x = on fulfilled(this . value);+resolve(x);+} catch(e){+reject(e);+}+})+this . onrejectedcallbacks . push(()= & gt;{ // todo..+try {+let x = on rejected(this . reason);+resolve(x);+} catch(e){+reject(e);+} ++})+}+})++ return promise 2;+}}我们注意到我们把回调的执行逻辑放在了promise2里面。这样做的原因是我们需要使用onFufilled的返回值来解析promises 2,这也是为什么then callback的返回值会传递给下一个then的原因。 promise完整版和规范有一点差距。那么注册的回调都是异步执行的。如果当时注册的回调的返回值是一个函数或者一个对象,在这里求解会稍微复杂一点。我们先来看看规范是如何定义Promise2 = Promise1的。然后(完成时,拒绝时);of onfulfilled或onRejected的返回值2.3.1如果promise和x引用同一个对象,使用TypeError作为拒绝的原因)promise。 2.3.2如果x是一个承诺,则采用承诺状态2.3.2.1。如果x是请求状态(待定),承诺必须保持待定,直到履行或拒绝2.3.2.2如果x是完成状态(已完成),用相同的值完成履行承诺2.3.2.2。如果x被拒绝,reject promises 2 . 3 . 3同样的原因。另外,如果X是一个对象或者一个对象,2.3.3.1让X是x.then.2.3.3.2如果检索到的x.then属性的结果是一个异常的e,用e作为原因拒绝promise2.3.3.3如果then是一个方法,用X调用它如下,第一个参数是resolvePromise,第二个参数是reject promise,其中:2 . 3 . 3 . 1如果/当resolvePromise被值Y调用时,运行[[resolve]] (promise,y) 2.3.3 用r拒绝)promise2.3.3.3.3如果同时调用resolvePromise和rejectPromise,或者重复调用同一个参数,则执行第一个调用,忽略任何进一步的调用。 2.3.3.3.4如果调用随后抛出异常e2.3.3.3.4.1如果已调用resolvePromise或rejectPromise,则忽略它。 2.3.3.3.4.2或者,用E作为理由拒绝)承诺规范可能有点复杂,需要你慢慢消化。这里我直接贴代码,我会在代码里标注每个规范的实现点。 Const status = {pending:' pending ',fufilled:' fufilled ',rejected:' rejected ' }//我们的promise可以共享函数resolvePromise(x,Promise2,resolve,reject) {//规范2.3.1 if (promise2 == x) {//防止自己等待自己完成返回reject(new type error(' error ')}//规范2 . 3 . 3 if((x = = = ' object ' & amp;x!= = null)| | x的类型= =' function') {//x可以是一个被调用的对象或函数;Try {//规范的2.3.3.1 let then = x . then;if(type of then = = ' Function '){//2.3.3.3 then . call(x,Function(y) {//规范2.3.3.3 if(called)return called = true;//规范2.3.3.3.1 resolve promise (y,promise 2,resolve,reject);}、function(r) {//规范2.3.3.3 if(called)return called = true;//规范2 . 3 . 3 . 3 . 2 reject(r);})} else { resolve(x);//此时X为普通对象}} catch (e) {//规范2.3.3.3.4.1 if(被调用)return called = true//2.3.3.3.4规范的reject(e);//获取then时抛出错误} } else { resolve(x);// x是原始数据类型,不能是promise} // Call resolve}类promise { constructor(executor){ this;地位=地位;如果没有权限,则直接挂起;this.value = undefinedthis.reason = undefinedthis . onresolvedcallbacks =[];//this.onRejectedCallbacks = []存储成功的回调;//constra solve =(val)= >存储失败回调的位置;{if(val instanceof Promise){ //如果是Promise,继续递归解析返回val.then(resolve,reject) } if (this.status == STATUS。待定){ this.status = STATUS。填充的;this.value = val//publish this . onresolvedcallbacks . foreach(fn = >;fn());} } const reject =(原因)= & gt{ if (this.status == STATUS。待定){ this.status = STATUS。被拒;this.reason = reason//腹部this . onrejectcallbacks . foreach(fn = >;fn());} }尝试{ executor(resolve,reject);} catch(e){//fail logic reject(e)} } then(on fulfilled,on rejected){//swtich scope//fulfilled上的可选参数= on fulfilled的类型= =' function '?未完成:x = & gtx on rejected = type of on rejected = = = ' function '?on rejected:err = & gt;{ throw err } let Promise 2 = new Promise((resolve,reject)= & gt;{ if (this.status === STATUS。FUFILLED) { //到....setTimeout(()= & gt;{ try { let x = on fulfilled(this . value);resolvePromise(x,promise2,resolve,reject)} catch(e){ reject(e);} }, 0);} if (this.status === STATUS。已拒绝){ setTimeout(()= & gt;{ try { let x = on rejected(this . reason);resolvePromise(x,promise2,resolve,reject)} catch(e){ reject(e);} }, 0);} if(this . status = = status . pending){//decorator模式切片编程this . onresolvedcallbacks . push(()= >;{ // todo..setTimeout(()= & gt;{ try { let x = on fulfilled(this . value);resolvePromise(x,promise2,resolve,reject)} catch(e){ reject(e);} }, 0);})this . onrejectedcallbacks . push(()= & gt;{ // todo..setTimeout(()= & gt;{ try { let x = on rejected(this . reason);resolvePromise(x,promise2,resolve,reject)} catch(e){ reject(e);} }, 0);}) } });回报承诺2;}}}测试工具推荐一个测试promise能否标准化的工具——promises-aplus-tests。使用方法如下:全局安装promises-aplus-tests,然后添加以下代码promise . deferred = function(){ let DFD = { };DFD . Promise = new Promise((resolve,reject)= & gt;{ dfd.resolve = resolvedfd.reject = reject })返回dfd}module.exports = Promise然后直接在控制台运行promises-aplus-tests:可以看到我们的Promise成功通过了测试。 Image.png总结道,希望这篇文章能帮助你更深刻地认识到承诺的不易,也希望得到你的赞许。


  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【技术支持|常见问题】1556原创ng8文章搜索页面不齐(2024-05-01 14:43)
【技术支持|常见问题】1502企业站群-多域名跳转-多模板切换(2024-04-09 12:19)
【技术支持|常见问题】1126完美滑屏版视频只能显示10个(2024-03-29 13:37)
【技术支持|常见问题】响应式自适应代码(2024-03-24 14:23)
【技术支持|常见问题】1126完美滑屏版百度未授权使用地图api怎么办(2024-03-15 07:21)
【技术支持|常见问题】如何集成阿里通信短信接口(2024-02-19 21:48)
【技术支持|常见问题】算命网微信支付宝产品名称年份在哪修改?风水姻缘合婚配对_公司起名占卜八字算命算财运查吉凶源码(2024-01-07 12:27)
【域名/主机/服务器|】帝国CMS安装(2023-08-20 11:31)
【技术支持|常见问题】通过HTTPs测试Mozilla DNS {免费源码}(2022-11-04 10:37)
【技术支持|常见问题】别告诉我你没看过邰方这两则有思想的创意广告! (2022-11-04 10:37)

联系我们
Q Q:375457086
Q Q:526665408
电话:0755-84666665
微信:15999668636
联系客服
企业客服1 企业客服2 联系客服
86-755-84666665
手机版
手机版
扫一扫进手机版
返回顶部