范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

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

  1.定义对象分析经典Promise对象
  经典的 Promise  对象结构代码如下:
  1.查看空 Promise  对象的结构和输出结果: var p = new Promise(function(resolve,reject){ console.log(resolve,reject) }) console.log(p)
  输出结果如下: ƒ () { [native code] } ƒ () { [native code] } Promise [[Prototype]]: Promise [[PromiseState]]: "pending" [[PromiseResult]]: undefined
  2.查看 fulfilled  状态下的 Promise  对象: var p = new Promise(function(resolve,reject){   resolve("已完成") }) console.log(p)
  输出结果如下: Promise {: "已完成"} [[Prototype]]: Promise [[PromiseState]]: "fulfilled" [[PromiseResult]]: "已完成"
  3.查看 rejected  状态下的 Promise  对象: var p = new Promise(function(resolve,reject){ reject("已拒绝") }) console.log(p)
  输出结果如下: Promise {: "已拒绝"} [[Prototype]]: Promise [[PromiseState]]: "rejected" [[PromiseResult]]: "已拒绝" Uncaught (in promise) 已拒绝Promise对象的基本结构定义
  根据 Promise  对象的特点分析, Promise  存在状态属性和 Promise  的值的属性。初始化 Promise  时需要传入一个回调函数来进行对象的基本设置,回调函数具备两个参数 resolve  和 reject  ,两个参数均为函数。所以初始化代码如下: function MyPromise(fn){   //promise的初始状态为pending,可变成fulfilled或rejected其中之一   this.promiseState = "pending"   this.promiseValue = undefined   var resolve = function(){    }   var reject = function(){    }   if(fn){     fn(resolve,reject)   }else{     throw("Init Error,Please use a function to init MyPromise!")   } }
  根据对象特性,初始化 Promise  时的回调函数是同步执行的,所以此时的 fn  直接调用即可。
  在调用 resolve  和 reject  时,需要将 Promise  对象的状态设置为对应的 fulfilled  和 rejected  ,其中需要传入 Promise  当前的结果,所以此时应该将 resolve  和 reject  修改为如下结构。 //保存上下文对象 var _this = this var resolve = function(value){   if(_this.promiseState == "pending"){     _this.promiseState = "fulfilled"     _this.promiseValue = value   }   } var reject = function(value){   if(_this.promiseState == "pending"){      _this.promiseState = "rejected"          _this.promiseValue = value   }  }
  定义完内部结构之后需要思考 Promise  在状态变更为 fulfilled  以及状态变更为 rejected  时对应的 then  和 catch  会相应执行,所以需要将对象的两个函数初始化: MyPromise.prototype.then = function(callback){  } MyPromise.prototype.catch = function(callback){  }
  那么初始对象的结构应该整体是这样的: function MyPromise(fn){   //promise的初始状态为pending,可变成fulfilled或rejected其中之一   this.promiseState = "pending"   this.promiseValue = undefined   var _this = this   var resolve = function(value){     if(_this.promiseState == "pending"){       _this.promiseState = "fulfilled"       _this.promiseValue = value     }     }   var reject = function(value){      if(_this.promiseState == "pending"){        _this.promiseState = "rejected"        _this.promiseValue = value     }    }   if(fn){     fn(resolve,reject)   }else{     throw("Init Error,Please use a function to init MyPromise!")   } } MyPromise.prototype.then = function(callback){  } MyPromise.prototype.catch = function(callback){  }实现then的调用
  在实现了初始结构之后,我们需要使用 MyPromise  按照 Promise  的方式进行编程,来实现他的流程控制部分了。首先我们需要让 then  跑起来。
  定义调用代码: var p = new MyPromise(function(resolve,reject){   resolve(123) }) console.log(p) p.then(function(res){   console.log(res) })
  此时执行代码时控制台会输出如下内容: MyPromise promiseState: "fulfilled" promiseValue: 123 [[Prototype]]: Object
  我们发现我们定义的 Promise  对象状态已经变更但是 then  中的回调函数没有执行。
  接下来我们实现 then  的触发: //在MyPromise中改造该部分代码如下 //定义then的回调函数 this.thenCallback = undefined  var resolve = function(value){   if(_this.promiseState == "pending"){     _this.promiseState = "fulfilled"     _this.promiseValue = value     //异步的执行then函数中注册的回调函数     setTimeout(function(){       if(_this.thenCallback){         _this.thenCallback(value)       }     })   }  }//在then中编写如下代码 MyPromise.prototype.then = function(callback){   //then第一次执行时注册回调函数到当前的Promise对象   this.thenCallback = function(value){     callback(value)   } }
  在两处改造完成之后访问网页会发现控制台上可以输出 then  函数中的回调执行的结果并且该结果的参数就是 resolve  传入的值。 MyPromise {     promiseState: "fulfilled",      promiseValue: 123,      thenCallback: undefined } promise.html:51 123
  当前代码效果如下: function MyPromise(fn){   //promise的初始状态为pending,可变成fulfilled或rejected其中之一   this.promiseState = "pending"   this.promiseValue = undefined   var _this = this   //定义then的回调函数   this.thenCallback = undefined    var resolve = function(value){     if(_this.promiseState == "pending"){       _this.promiseState = "fulfilled"       _this.promiseValue = value       //异步的执行then函数中注册的回调函数       setTimeout(function(){         if(_this.thenCallback){           _this.thenCallback(value)         }       })     }   }   var reject = function(value){     if(_this.promiseState == "pending"){       _this.promiseState = "rejected"       _this.promiseValue = value     }   }   if(fn){     fn(resolve,reject)   }else{     throw("Init Error,Please use a function to init MyPromise!")   } } MyPromise.prototype.then = function(callback){   //then第一次执行时注册回调函数到当前的Promise对象   this.thenCallback = function(value){     callback(value)   } } MyPromise.prototype.catch = function(callback){  } var p = new MyPromise(function(resolve,reject){   resolve(123) }) console.log(p) p.then(function(res){   console.log(res) })实现then的异步链式调用
  通过上面的编程已经可以实现 then  自动触发,但是当前我们如果将代码变成如下效果时只有一个 then  能执行。而且控制台会报错 var p = new MyPromise(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:52 Uncaught TypeError: Cannot read properties of undefined (reading "then")     at promise.html:52 (anonymous) @ promise.html:52 promise.html:51 123
  针对该情况,我们需要对 Promise  的流程控制代码做进一步的加强以实现链式调用,并且在链式调用的过程中将每次的结果顺利的向下传递。 //resolve部分代码实现 var resolve = function(value){   if(_this.promiseState == "pending"){     _this.promiseValue = value     _this.promiseState = "fulfilled"     //当传入的类型是Promise对象时     if(value instanceof MyPromise){       value.then(function(res){         _this.thenCallback(res)       })     }else{       //当传入的数据类型是普通变量时       setTimeout(function(){         if(_this.thenCallback){           _this.thenCallback(value)         }       })     }   } } //then函数代码实现 MyPromise.prototype.then = function(callback){   var _this = this   return new MyPromise(function(resolve,reject){     _this.thenCallback = function(value){       var callbackRes = callback(value)       resolve(callbackRes)     }   }) }
  将 then  代码修改为如下之后我们将调用代码更改如下 var p = new MyPromise(function(resolve){   resolve(new MyPromise(function(resolve1){     resolve1("aaa")   })) }) p.then(function(res){   console.log(res)   return 123 }).then(function(res){   console.log(res)   return new MyPromise(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:57 aaa test.html:60 123 test.html:67 Promise
  当前状态的代码如下 function MyPromise(fn){   var _this = this   this.promiseValue = undefined   this.promiseState = "pending"   this.thenCallback = undefined   this.catchCallback = undefined   var resolve = function(value){     if(_this.promiseState == "pending"){       _this.promiseValue = value       _this.promiseState = "fulfilled"       if(value instanceof MyPromise){          value.then(function(res){           _this.thenCallback(res)         })       }else{         setTimeout(function(){           if(_this.thenCallback){             _this.thenCallback(value)           }         })       }     }   }   var reject = function(err){    }   if(fn){     fn(resolve,reject)   }else{     throw("Init Error,Please use a function to init MyPromise!")   } } MyPromise.prototype.then = function(callback){   var _this = this   return new MyPromise(function(resolve,reject){     _this.thenCallback = function(value){       var callbackRes = callback(value)       resolve(callbackRes)     }   }) } var p = new MyPromise(function(resolve){   resolve(new MyPromise(function(resolve1){     resolve1("aaa")   })) })实现catch的流程处理
  当 Promise  的对象触发 reject  操作的时候他的状态会变更为 rejected  ,此时会触发 catch  函数,并且 catch  函数触发后流程结束。
  首先仿照 then  的方式在 MyPromise  对象中定义好初始通知函数 //定义catch的回调函数 this.catchCallback = undefined var reject = function(err){   if(_this.promiseState == "pending"){     _this.promiseValue = err     _this.promiseState = "rejected"     setTimeout(function(){       if(_this.catchCallback){         _this.catchCallback(err)       }     })   } }
  然后在 catch  函数中做如下处理 MyPromise.prototype.catch = function(callback){   var _this = this   return new MyPromise(function(resolve,reject){     _this.catchCallback = function(errValue){       var callbackRes = callback(errValue)       resolve(callbackRes)     }   }) }
  调用代码如下 var p = new MyPromise(function(resolve,reject){   reject("err") }) p.catch(function(err){   console.log(err) })
  当运行此时代码时我们会发现我们的 Promise  对象在控制台上可以直接触发 catch  的回调执行并输出对应的结果 MyPromise {promiseValue: "err", promiseState: "rejected", thenCallback: undefined, catchCallback: ƒ} test.html:73 err实现跨对象执行catch
  在上面的案例中已经可以执行 MyPromise  的 catch  函数了,但是如果将调用代码改为如下行为会发现 catch  函数不会执行 var p = new MyPromise(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  再去检测是否存在 thenCallback  var reject = function(err){   if(_this.promiseState == "pending"){     _this.promiseValue = err     _this.promiseState = "rejected"     setTimeout(function(){       if(_this.catchCallback){         _this.catchCallback(err)       }else if(_this.thenCallback){         _this.thenCallback(err)       }else{         throw("this Promise was reject,but can not found catch!")       }     })   } }
  该步骤操作完毕之后我们需要将 then  函数中的逻辑再次更改为如下 MyPromise.prototype.then = function(callback){   var _this = this   //实现链式调用并且每个节点的状态是未知的所以每次都需要返回一个新的Proimse对象   return new MyPromise(function(resolve,reject){     //then第一次执行时注册回调函数到当前的Promise对象     _this.thenCallback = function(value){       //判断如果进入该回调时Promise的状态为rejected那么就直接触发后续Promise的catchCallback       //直到找到catch       if(_this.promiseState == "rejected"){         reject(value)       }else{         var callbackRes = callback(value)         resolve(callbackRes)       }	     }   }) }
  修改如下之后调用代码改造为 var p = new MyPromise(function(resolve,reject){   reject("err") }) p.then(function(res){   console.log(res)   return 111 }).then(function(res){   console.log(res)   return 111 }).then(function(res){   console.log(res)   return 111 }).catch(function(err){   console.log(err) }) console.log(p)
  输出结果为 MyPromise {promiseValue: "err", promiseState: "rejected", catchCallback: undefined, thenCallback: ƒ} test.html:91 err实现链式调用的中断
  本文仅介绍通过返回 Promise  对象来中断链式调用,首先在 Promise  的原型对象上增加 reject  方法如下: MyPromise.reject = function(value){   return new MyPromise(function(resolve,reject){     reject(value)   }) }
  然后初始化如下调用代码 var p = new MyPromise(function(resolve,reject){   resolve(123) }) console.log(p) p.then(function(res){   console.log("then1执行")   return 456 }).then(function(res){   console.log("then2执行")   return MyPromise.reject("中断了") }).then(function(res){   console.log("then3执行")   return 789 }).then(function(res){   console.log("then4执行")   return 666 }).catch(function(err){   console.log("catch执行")   console.log(err) })
  最后修改调试代码中的 then  MyPromise.prototype.then = function(callback){   var _this = this   return new MyPromise(function(resolve,reject){     _this.thenCallback = function(value){       if(_this.promiseState == "rejected"){         reject(value)       }else{         var callbackRes = callback(value)         if(callbackRes instanceof MyPromise){           if(callbackRes.promiseState == "rejected"){             callbackRes.catch(function(errValue){               reject(errValue)             })           }         }else{           resolve(callbackRes)         }       }     }   }) }
  根据代码分析处理逻辑,然后查看运行结果: MyPromise {promiseState: "fulfilled", promiseValue: 123, thenCallback: undefined, catchCallback: undefined} promise.html:100 then1执行 promise.html:103 then2执行 promise.html:112 catch执行 promise.html:113 中断了
  最后我们发现在返回 Promise.reject()  之后 then  的链式调用便中断了。 实现all和race
  1.Promise.all的实现 MyPromise.all = function(promiseArr){   var resArr = []   var errValue = undefined   var isRejected = false   return new MyPromise(function(resolve,reject){     for(var i=0;i {             return item.promiseState == "fulfilled"           })           if(r){             resolve(resArr)           }         }).catch(function(err){           isRejected = true           errValue = err           reject(err)         })       })(i)        if(isRejected){         break       }     }   }) }
  1. Promise.race  的实现 MyPromise.race = function(promiseArr){   var end = false   return new MyPromise(function(resolve,reject){     for(var i=0;i {             return item.promiseState == "fulfilled"           })           if(r){             resolve(resArr)           }         }).catch(function(err){           isRejected = true           errValue = err           reject(err)         })       })(i)        if(isRejected){         break       }     }   }) }  MyPromise.race = function(promiseArr){   var end = false   return new MyPromise(function(resolve,reject){     for(var i=0;i
花生是糖尿病的导火索?若想胰岛强壮,3种食物尽量少碰今年56岁的王大娘就在上个月的体检中被确诊了糖尿病。事情是这个样子的,王大娘虽然年龄越来越大了,但是身体一直以来都还挺不错的,几乎没有什么疾病。但是前段时间,王大娘的身体却出现了一85岁马玉琴遗嘱曝光,儿孙成最大赢家,李玉成神情落寞啃大馒头说起马玉琴和李玉成这对老妻少夫,想必大家都有所了解,因为相差32岁他们的爱情一直不被周围人认可,刚结婚的俩人可以说一贫如洗,过了很长时间的苦日子。好在夫妻俩接触短视频之后,通过这个孕妇肚型不能判断胎儿性别,却能决定孕妇遭多少罪,尤其是悬浮肚通常情况下,胎儿在孕16周后开始显怀,孕妇的孕肚肚型更为明显。不过,虽然是同期孕妇,但就是她们的肚型显现却有明显不同,比如说生活中比较常见的尖肚圆肚悬浮肚等。老人们总说,尖肚是男娃学霸高考239分,所有人都不相信,老师调阅监控后,这才恍然大悟在湖南的小山村里,有这样一位学霸。他一直是年级第一,学校几乎所有的老师都认识他。他是寒门贵子,因为家里贫困他非常争气,总是拿出最好的成绩单交给辛苦的父母。可在高考结束后,经过查分,嘎子要花8亿拍战争片,自称一套装备80万人民币?看完我绷不住了军武次位面作者L分队嘎子进村?因为潘嘎之交而被全网热议的嘎子谢孟伟,最近又因为一则报道火了,在由他主演的新电影硬汉狙击的宣发文章当中,网传他自称电影投资8个亿,他身上的一套装备将近神回复长城这么矮能拦住什么呢?看完神评服了,好有道理难道是我打开的方式不对一般我是不会笑的,你把后面的婆婆给逗笑啦台下十年功,台上一分钟,没有努力哪里来的成功谁还没有一两手的压箱底绝活呀怕是想逃离这个地方,人后拼了命的生长二哈我说不爱山东中考专区陪你一举高中旗开得胜鲁网6月14日讯为方便我省考生及家长更好更快地查询中考成绩及录取结果,省教育厅联合省大数据局依托爱山东政务服务平台,通过渠道整合集中发布的形式,上线覆盖全省16市的中考专区。实现全案例山东67岁大妈怀孕,不顾子女反对坚持生下,丈夫养得起大家都知道,女性是有一个正常的生育年龄的,过了这个年龄就很难生育,不仅是因为高龄妇女受孕难,更是因为高龄产妇生产风险大,很少有人在40岁之后还能怀孕,而在2019年,山东枣庄有一6上海外国语大学男生向女生咖啡杯里投异物,结果刑不刑?近日,媒体报道,上海外国语大学一名男生在图书馆内,给一位女生的杯子里投牛磺酸泡腾片。女生回到座位后察觉咖啡味道不对,遂没敢再喝,就把咖啡倒掉,并向学校保卫部门报告。经学校调查,发现都体头版基耶利尼称赞加蒂贝洛蒂将告别都灵直播吧6月14日讯今天都灵体育报聚焦了尤文和都灵的转会问题。尤文方面,基耶利尼高度称赞了加蒂,他表示加蒂在盯人方面很强,并且技术非常全面。他还表示加蒂具备效力尤文所需的那种个性,现贤合庄关店潮,流量明星难圆商家品牌梦前段时间,关于贤合庄加盟商维权的相关内容被网友关注并讨论着,6月8日,贤合庄卤味火锅就加盟商维权一事发布声明,称对捏造事实,采用割韭菜和跑路等主观恶意词汇对其进行攻击的行为,会通过
银河系50亿年前有大量外星人?反思人类科技,未来能找到它们吗?在天文学研究领域有一项研究表明是这样说到的。天文学家认为在银河系中很有可能有大量的外星文明曾经存在过。但是现在他们都已经灭亡了。天文学家用公式详细地描绘出了银河系从开始到现在的模型无实用,不香港,高交会上的香港黑科技有多实用?来源香港经济导报社为期5天的高交会即将接近尾声,我们来细数一下本届高交会香港的精彩表现。位于深圳会展中心1B52的香港馆,由香港创新科技署及香港贸易发展局合办。此外还有香港创科展区一文揭秘Web3。0千亿赛道之智能合约钱包对Web3。0世界好奇的用户有很多,然而在踏入区块链大门之前,一些问题拦住了很多人。对此,本文从智能合约钱包的角度切入,对智能合约钱包的演进历史技术特征使用场景及市场上主流的产品进小红书在私募市场上的隐含价值损失高达一半小红书,这个大受欢迎的社交媒体平台,是中国互联网当中对应Instagram的角色,该平台拥有千禧一代女性的忠实追随者和2亿活跃用户的受众,曾在一轮筹款中获得了200亿美元的估值,并路过西藏无人区,看到餐馆建议别停下来吃,价格不是一般人能给的中国的经济发展越来越好,人们的生活水平也提高了。随着钱包的鼓起来,人们有了更多的旅行机会。除了定期旅游,人们长期生活在繁华的城市,他们想去一些偏远的地方放松一下。这就是为什么近年来力争三年全球第一的背后,小米在国内市场正经历水土不服文小伊评科技在2021年8月16日,小米雷总在我的梦想,我的主题发布会上,曾立下了一个Flag,要在三年内超越三星成为世界第一。距离雷总立下这个Flag已经过去了14个月,时间基本美版14promax全新未激活,价格便宜,缺点没卡槽这两天看到海鲜市场有不少商家都出售这种美版全新iPhone14ProMax,至于为什么这么便宜?不是iPhone本身品质的原因,而是今年的美版已经没有了实体卡槽。也就是说如果你买了人民日报和音彰显理性自信负责任的大国担当11月14日至19日,习近平主席应邀赴印度尼西亚巴厘岛出席二十国集团(G20)领导人第十七次峰会赴泰国曼谷出席亚太经合组织(APEC)第二十九次领导人非正式会议并对泰国进行访问。从海外蔚来荷兰首座换电站建成,已在欧洲五国完成换电布局文懂车帝原创彩丽美懂车帝原创行业日前,据国内媒体报道,蔚来在荷兰首座换电站建成,将于12月1日正式上线运营。至此,蔚来在欧洲五国(挪威德国荷兰丹麦瑞典)布局的换电站均已落地。蔚来在深圳高交会闭幕1700多项新产品新技术首次亮央广网深圳11月21日消息(记者彭艺娑)展览面积40万平方米为历届最大1700多项新产品新技术首次亮相举办各类论坛等活动148场28个国家和地区21。4万人次观众现场参观11月19茅台酱香系列酒营收9个月内破百亿,舍得将推进舍得老酒馆项目茅台近日,2022年第106届糖酒会茅台酱香系列酒经销商座谈会召开,会议围绕工作中存在的问题,受疫情影响经济疲软怎样做好系列酒销售,茅台1935酒的营销推广建议等3方面内容进行交流