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

十几行代码教你实现最简单版本的promise

时间:2023-03-30 13:36:44 CSS

最近在研究promise的实现。本文用十几行代码实现了一个简单的promise;以帮助读者对promise有更深入的了解。本文中实现的承诺遵循Promises/A+的规范。阅读本文时,假设您了解promise的基本用法和一些简单的es6语法;如果你还没有掌握promise的基本使用,请学习后再回来。推荐看《promise迷你书》、《你不知道的js》和阮一峰老师的《ECMAScript 6 入门》。promise的核心实现首先,让我们看一下promise的基本用法:varp=newMyPromise((resolve)=>{setTimeout(()=>{resolve(20)},300)})p.then((msg)=>console.log(msg));MyPromise是一个构造函数,这个构造函数将被传递一个函数;函数中有两个参数,分别是resolve和reject两个函数。另一个promise具有三种状态:PENDING、RESOLVED和REJECTED。所以我们有以下代码:constPENDING=0;const已解决=1;const拒绝=2;functionMyPromise(func){letstate=PENDING;让值=空;函数解析(新值){值=新值;状态=已解决;}函数拒绝(错误){值=错误;状态=拒绝;}func(resolve,reject);}然后我们实现then函数,每次执行then函数都会返回一个新的promise。this.then=function(onFullFill,onReject){returnnewMyPromise((resolve,reject)=>{})}传递给then函数的返回值onFullFill函数会传递给第二个thenonFullFill。那就是能够使用p.then((msg)=>msg).then(data=>console.log(data));这行代码实际上是什么?我们把上面的代码改造一下:p.then(functionfn1(msg){returnmsg;}).then(functionfn2(data){console.log(data);})//上面代码的本质fn2(fn1(msg))我们如何在then函数中执行resolve函数呢?首先必须执行resolve函数,因为它需要改变p.then()产生的promise的状态;其次,resolve函数还必须接收onFullFill执行的值,传递给下一个回调函数。你可能已经想到了这个解决方案:constPENDING=0;const已解决=1;const拒绝=2;functionMyPromise(func){letstate=PENDING;让值=空;函数解析(新值){值=新值;状态=已解决;}函数拒绝(错误){值=错误;状态=拒绝;}this.then=function(onFullFill,onReject){returnnewMyPromise((resolve,reject)=>{resolve(onFullFill(value));})}func(resolve,reject);}varp=newMyPromise((resolve)=>{setTimeout(()=>{resolve(20)},300)})p.then((msg)=>msg).then(data=>console.log(data));但是当你拼凑上面的代码并执行它时;打印出来的是空的。为什么?因为setTimeout(fn,300)这行代码是异步执行的,当状态在promise!==RESOLVED时,这行代码resolve(onFullFill(value));不应该被执行。所以我们有以下优化:functionMyPromise(func){letstate=PENDING;让值=空;让处理程序=[];函数解析(新值){值=新值;状态=已解决;handlers.forEach(handler=>handle(handler));}函数拒绝(错误){值=错误;状态=拒绝;}functionhandle(handler){if(state===PENDING){处理程序。推(处理程序);返回;处理程序。解决(处理程序。onFullFill(值));}this.then=function(onFullFill,onReject){returnnewMyPromise((resolve,reject)=>{handle({resolve:resolve,onFullFill:onFullFill})})}func(resolve,reject);}这样,我们会在then函数中执行handle函数和resolve函数,但是只有在resolve函数执行完之后才会执行handler.resolve(handler.onFullFill(value))。现在还有一个问题,如果Promise中封装的不是异步操作,而是同步操作;那么resolve函数将在then函数之前执行。varp=newMyPromise((resolve,reject)=>{resolve('synchronousoperation')})p.then(console.log)所以我们在resolve中执行回调的时候,应该是异步执行的:functionresolve(newValue){价值=新价值;状态=已解决;setTimeout(()=>{handlers.forEach(handler=>handler(handler));},0)}同时,由于在then函数中可以接收到一个promise;我们需要case:functionresolve=(newValue)=>{if(newValue&&(typeofnewValue==='object'||typeonewValue==='function'){letthen=newValue.thenif(typeofthen==='function'){returnthen.call(newValue,resolve)}state=FULFILLED;value=newValue;setTimeout(()=>{handlers.forEach(handler=>{handler(handler)})},0)}到这里,我们已经完成了一个基本的promise实现。