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);}// 使用Promisevar 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);}// 使用Promisevar 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+的实现步骤详解的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2758187.html

(0)
上一篇 2025年3月8日 08:08:13
下一篇 2025年3月8日 08:08:20

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 前端中排序算法实例详解

    这次给大家带来前端中排序算法实例详解,前端中排序算法使用的注意事项有哪些,下面就是实战案例,一起来看一下。 前言 前天看到知乎上有一篇文章在吐槽阮一峰老师的快速排序算法,这里插一句题外话,我觉得人非圣贤孰能无过,尽信书不如无书,学习的过程也…

    2025年3月8日 编程技术
    200
  • 前端页面内实现左右摇摆广告

    这次给大家带来前端页面内实现左右摇摆广告,前端页面内实现左右摇摆广告的注意事项有哪些,下面就是实战案例,一起来看一下。 代码解读 定义 dom,容器中包含公告牌、挂公告牌的细绳和固定绳子的 3 个图钉: THANKS 登录后复制 居中显示:…

    编程技术 2025年3月8日
    200
  • React中setState使用详解

    这次给大家带来React中setState使用详解,React中setState使用的注意事项有哪些,下面就是实战案例,一起来看一下。 抛出问题 class Example extends Component { contructor ()…

    2025年3月8日
    200
  • React中路由使用详解

    这次给大家带来react中路由使用详解,react中路由使用的注意事项有哪些,下面就是实战案例,一起来看一下。 路由 通过 URL 映射到对应的功能实现,React 的路由使用要先引入 react-router.js。  注意:  reac…

    编程技术 2025年3月8日
    200
  • React中生命周期使用详解

    这次给大家带来React中生命周期使用详解,React中生命周期使用的注意事项有哪些,下面就是实战案例,一起来看一下。 生命周期 React 是一个由虚拟 DOM 渲染成真实 DOM 的过程,这个过程称为组件的生命周期。React 把这个周…

    编程技术 2025年3月8日
    200
  • React中组件通信使用详解

    这次给大家带来React中组件通信使用详解,React中组件通信使用的注意事项有哪些,下面就是实战案例,一起来看一下。 组件通信 在这里只讲 React 组件与组件本身的通信,组件通信主要分为三个部分: 父组件向子组件通信:父组件向子组件传…

    编程技术 2025年3月8日
    200
  • React中表单使用详解

    这次给大家带来React中表单使用详解,React中表单使用的注意事项有哪些,下面就是实战案例,一起来看一下。 表单 React 是个单向数据流的框架,所以在表单元素与其它 DOM 元素有所不同,而且和双向绑定的框架在操作上也有很大不一样。…

    编程技术 2025年3月8日
    200
  • 基于ajax的简单搜索实现方法

    这篇文章主要介绍了基于ajax的简单搜索实现方法,结合实例形式较为详细的分析了ajax调用实现搜索功能的具体步骤与相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下 本文实例讲述了基于ajax的简单搜索实现方法。分享给大家供大家参考,具体…

    编程技术 2025年3月8日
    200
  • React中样式绑定使用详解

    这次给大家带来React中样式绑定使用详解,React中样式绑定使用的注意事项有哪些,下面就是实战案例,一起来看一下。 普通样式名称使用 —— className app.css .c1{ color: red; width: 100%; …

    编程技术 2025年3月8日
    200
  • React中state使用详解

    这次给大家带来React中state使用详解,React中state使用的注意事项有哪些,下面就是实战案例,一起来看一下。 state state 可以理解成 props,不一样的在于 props 是只读的,而 state 是可读写。当 s…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论