您好,欢迎访问一九零五行业门户网

PromiseA+的实现步骤详解

这次给大家带来promisea+的实现步骤详解,promisea+实现的注意事项有哪些,下面就是实战案例,一起来看一下。
promise手写一个promisea+的实现。注意这里只是模拟,实际上原生的promise在事件队列中属于microtask。这里用settimeout模拟不是特别恰当。因为settimeout是一个macrotask。
1. 最简单的基本功能/**  * 定义promise  * 先实现一个最简单的。用settimeout模拟一个异步的请求。  */ function promise(fn){   var value= null;   var callbacks = [];   this.then = function(onfulfilled) {     callbacks.push(onfulfilled);   }   function resolve(value){     callbacks.foreach(function(cb){       cb(value);     })   }   fn(resolve); } // 使用promise var p = new promise(function(resolve){   settimeout(function(){     resolve('这是响应的数据')   },2000) }) p.then(function(response){   console.log(response); })
2.链式调用/**  * 先看一下前一个例子存在的问题  * 1.在前一个例子中不断调用then需要支持链式调用,每次执行then都要返回调用对象本身。  * 2.在前一个例子中,当链式调用的时候,每次then中的值都是同一个值,这是有问题的。其实第一次then中的返回值,应该是第二次调用then中的函数的参数,依次类推。  * 所以,我们进一步优化一下代码。  *   */ function promise(fn){   var value= null;   var callbacks = [];   this.then = function(onfulfilled) {     callbacks.push({f:onfulfilled});     return this;   }   function resolve(value){     callbacks.map(function(cb,index){       if(index === 0){         callbacks[index].value = value;       }       var rsp = cb.f(cb.value);       if(typeof callbacks[index+1] !== 'undefined'){         callbacks[index+1].value = rsp;       }     })   }   fn(resolve); } // 使用promise var p = new promise(function(resolve){   settimeout(function(){     resolve('这是响应的数据')   },2000) }) p.then(function(response){   console.log(response);   return 1; }).then(function(response){   console.log(response);   return 2;   }).then(function(response){   console.log(response); })
3. 异步/**  * 先看一下前一个例子存在的问题  * 1. 如果在then方法注册回调之前,resolve函数就执行了,怎么办?比如 new promise的时候传入的函数是同步函数的话,  * then还没被注册,resolve就执行了。。这在promisea+规范中是不允许的,规范明确要求回调需要通过异步的方式执行。  * 用来保证一致可靠的执行顺序。  *   * 因此我们需要加入一些处理。把resolve里的代码放到异步队列中去。这里我们利用settimeout来实现。  * 原理就是通过settimeout机制,将resolve中执行回调的逻辑放置到js任务队列末尾,以保证在resolve执行时,  * then方法的回调函数已经注册完成  *   */ function promise(fn){   var value= null;   var callbacks = [];   this.then = function(onfulfilled) {     callbacks.push({f:onfulfilled});     return this;   }   function resolve(value){     settimeout(function(){         callbacks.map(function(cb,index){           if(index === 0){             callbacks[index].value = value;           }           var rsp = cb.f(cb.value);           if(typeof callbacks[index+1] !== 'undefined'){             callbacks[index+1].value = rsp;           }         })     },0)   }   fn(resolve); } // 使用promise,现在即使是同步的立马resolve,也能正常运行了。 var p = new promise(function(resolve){     resolve('这是响应的数据') }) p.then(function(response){   console.log(response);   return 1; }).then(function(response){   console.log(response);   return 2;   }).then(function(response){   console.log(response); })
4. 状态机制/**  * 先看一下前一个例子存在的问题  * 1.前一个例子还存在一些问题,如果promise异步操作已经成功,在这之前注册的所有回调都会执行,  * 但是在这之后再注册的回调函数就再也不执行了。具体的运行下面这段代码,可以看到“can i invoke”并没有打印出来  * 想要解决这个问题,我们就需要加入状态机制了。具体实现看本文件夹下的另一个js文件里的代码。  *   */ function promise(fn){   var value= null;   var callbacks = [];   this.then = function(onfulfilled) {     callbacks.push({f:onfulfilled});     return this;   }   function resolve(value){     settimeout(function(){         callbacks.map(function(cb,index){           if(index === 0){             callbacks[index].value = value;           }           var rsp = cb.f(cb.value);           if(typeof callbacks[index+1] !== 'undefined'){             callbacks[index+1].value = rsp;           }         })     },0)   }   fn(resolve); } //  var p = new promise(function(resolve){     resolve('这是响应的数据') }) p.then(function(response){   console.log(response);   return 1; }).then(function(response){   console.log(response);   return 2;   }).then(function(response){   console.log(response); }) settimeout(function(){    p.then(function(response){      console.log('can i invoke?');    }) },0)
/**  * 在promise01.js中,我们已经分析了,我们需要加入状态机制  * 在这里实现一下promisea+中关于状态的规范。  *   * promises/a+规范中的2.1promise states中明确规定了,pending可以转化为fulfilled或rejected并且只能转化一次,  * 也就是说如果pending转化到fulfilled状态,那么就不能再转化到rejected。  * 并且fulfilled和rejected状态只能由pending转化而来,两者之间不能互相转换  *   */ function promise(fn){   var status = 'pending'   var value= null;   var callbacks = [];   this.then = function(onfulfilled) {     // 如果是pending状态,则加入到注册队列中去。     if(status === 'pending'){       callbacks.push({f:onfulfilled});       return this;     }     // 如果是fulfilled 状态,此时直接执行传入的注册函数即可。     onfulfilled(value);     return this;   }   function resolve(newvalue){     value = newvalue;     status = 'fulfilled';     settimeout(function(){         callbacks.map(function(cb,index){           if(index === 0){             callbacks[index].value = newvalue;           }           var rsp = cb.f(cb.value);           if(typeof callbacks[index+1] !== 'undefined'){             callbacks[index+1].value = rsp;           }         })     },0)   }   fn(resolve); } //  var p = new promise(function(resolve){     resolve('这是响应的数据') }) p.then(function(response){   console.log(response);   return 1; }).then(function(response){   console.log(response);   return 2;   }).then(function(response){   console.log(response); }) settimeout(function(){    p.then(function(response){      console.log('can i invoke?');    }) },1000)
/**  * 刚才的例子中,确实打印出了 can i invoke,但是之前then的注册函数的返回值,并没有打印出来。  * 也就是说 1 和 2 并没有被打印出来,看下面的注释  *   */ function promise(fn){   var status = 'pending'   var value= null;   var callbacks = [];   this.then = function(onfulfilled) {     if(status === 'pending'){       callbacks.push({f:onfulfilled});       return this;     }     onfulfilled(value);     return this;   }   function resolve(newvalue){     value = newvalue;     status = 'fulfilled';     settimeout(function(){         callbacks.map(function(cb,index){           if(index === 0){             callbacks[index].value = newvalue;           }           var rsp = cb.f(cb.value);           if(typeof callbacks[index+1] !== 'undefined'){             callbacks[index+1].value = rsp;           }         })     },0)   }   fn(resolve); } var p = new promise(function(resolve){     resolve('aaaaaa') }) p.then(function(response){   console.log(response);       return 1; }).then(function(response){   console.log(response);  // 这里应该打印的是45行返回的1,但是打印出来的确是aaaaaa   return 2;   }).then(function(response){   console.log(response); // 这里应该打印的是48行返回的2,但是打印出来的确是aaaaaa }) settimeout(function(){    p.then(function(response){      console.log('can i invoke?');    }) },1000) /**  * 问题的根源在于什么呢?  * 问题的根源是每次的then的返回值都是p,当状态是fulfilled,执行的是onfulfilled(value)  * 此处的value是p的value,也就是fulfilled状态的value。根据规范,promise应该是只能发射单值。  * 而我们设计了一个callback堆栈中有一系列的值。生生的把promise变成了多值发射。  *   * 所以,调整思路,每个then都应该返回一个promise,这个promise应该是一个全新的promise。  * 具体实现见下一个例子。  */
/**  * 根据刚才的分析,我们重新优化一下代码  * 1.去掉之前的多值设计  * 2.每次的then 返回的都是一个全新的promise  *  */ function promise(fn){   var status = 'pending'   var value= null;   var callbacks = [];   var self = this;   this.then = function(onfulfilled) {     return new promise(function(resolve){       function handle(value){         var res = typeof onfulfilled === 'function' ? onfulfilled(value) : value;         resolve(res);       }       // 如果是pending状态,则加入到注册队列中去。       if(status === 'pending'){         callbacks.push(handle);       // 如果是fulfilled 状态。       }else if(status === 'fulfilled'){           handle(value);       }     })   }   function resolve(newvalue){     value = newvalue;     status = 'fulfilled';          settimeout(function(){         callbacks.map(function(cb){           cb(value);         })     },0)   };   fn(resolve); } //  var p = new promise(function(resolve){     resolve('这是响应的数据') }) p.then(function(response){   console.log(response);   return 1; }).then(function(response){   console.log(response);   return 2;   }).then(function(response){   console.log(response); }) settimeout(function(){    p.then(function(response){      console.log('can i invoke?');    }) },1000) /**  * 运行一下,完美输出  * 先是输出“这是响应的数据”,然后是“1”,然后是“2”, 然后是“can i invoke?”  *   * 接下来我们要好好整理一下代码了。把一些公用的方法放到构造函数的原型上去。改造之后的例子见下一个例子  */
/**  * 根据刚才的分析,我们重新优化一下代码  * 1.把私有属性挂到实例上去  * 2.把公共方法挂到构造函数的原型上去  *  */ function promise(fn){   this.status = 'pending';   this.value= null;   this.callbacks = [];   var self = this;   function resolve(newvalue){     self.value = newvalue;     self.status = 'fulfilled';     settimeout(function(){       self.callbacks.map(function(cb){           cb(value);         })     },0)   }   fn(resolve); } promise.prototype = object.create(null); promise.prototype.constructor = promise; promise.prototype.then = function(onfulfilled){   var self = this;   return new promise(function(resolve){     function handle(value){       var res = typeof onfulfilled === 'function'?  onfulfilled(value) : value;       resolve(res);     }     if(self.status==='pending'){       self.callbacks.push(handle);     }else if(self.status ==='fulfilled'){       handle(self.value);     }   }) } // 使用 var p = new promise(function(resolve){     resolve('这是响应的数据') }) p.then(function(response){   console.log(response);   return 1; }).then(function(response){   console.log(response);   return 2;   }).then(function(response){   console.log(response); }) settimeout(function(){    p.then(function(response){      console.log('can i invoke?');    }) },1000)
5.处理注册的函数返回值是promise的情况/**  * 不出意料,又要抛出问题了。当then注册的回调函数返回的是promise的时候,从这个then之后的所有then的注册函数  * 都应该注册在新返回的promise上。直到遇到下一个回调函数的返回值也是promise。  *   * 实现思路:  * 在handle中判断注册函数返回的是否是promise。如果是的话,则resolve这个返回的promise的值,具体代码看一下36到38行  *   */ function promise(fn){   this.status = 'pending';   this.value= null;   this.callbacks = [];   var self = this;   function resolve(newvalue){     self.value = newvalue;     self.status = 'fulfilled';     settimeout(function(){       self.callbacks.map(function(cb){           cb(value);         })     },0)   }   fn(resolve); } promise.prototype = object.create(null); promise.prototype.constructor = promise; promise.prototype.then = function(onfulfilled){   var self = this;   var promise = new promise(function(resolve){     function handle(value){       var res = typeof onfulfilled === 'function'?  onfulfilled(value) : value;       if(res instanceof promise){         promise = res;         resolve(res.value);       }else {         resolve(res);       }     }     if(self.status==='pending'){       self.callbacks.push(handle);     }else if(self.status ==='fulfilled'){       handle(self.value);     }   })   return promise; } // 使用 var p = new promise(function(resolve){     resolve('这是响应的数据') }) p.then(function(response){   console.log(response);   return new promise(function(resolve){     resolve('testtest')   }) }).then(function(response){   console.log(response);   return 2;   }).then(function(response){   console.log(response); }) settimeout(function(){    p.then(function(response){      console.log('can i invoke?');      return new promise(function(resolve){         resolve('hhhhhh')       })    }).then(function(response){      console.log(response);    }) },1000)
相信看了本文案例你已经掌握了方法,更多精彩请关注其它相关文章!
推荐阅读:
react结合typescript和mobx步骤详解
react-router v4使用步骤详解
以上就是promisea+的实现步骤详解的详细内容。
其它类似信息

推荐信息