资讯专栏INFORMATION COLUMN

promise 基础版(雏形)

罗志环 / 2600人阅读

摘要:以下方式写提示未定义涉及闭包作用域链的问题改进方式调用实例化回调函数执行成功,并执行函数,此时在回调队列里面添加一一个函数,并将的参数传递出去。否则直接执行回调函数,不会由来触发的回调函数执行。

function Promise(fn){
    //需要一个成功时的回调
    var self = this
    var callback;
    //一个实例的方法,用来注册异步事件
    self.then = function(done){
      callback = done;
    }
    // resolve 比 then 先执行 此时 callback 不存在
    // 所以 加一个 setTimeout 让resolve 函数在回调队列的末尾
    // 为啥是0秒? 为啥处于回调队列末尾?
    //(权威指南)如果以0毫秒的超时时间来调用setTimeout(),那么指定的函数不会立即执
    // 行,相反会把它放到队列中去,等到前面处于等待状态的事件处理程序全部执行完成后,
    // 再“立即”调用它。
    // 以下 方式写 提示 resolve 未定义 涉及闭包 作用域链的问题
    // setTimeout(function () {
    //   function resolve(value){
    //      callback && callback(value);
    //   }
    // }, 0)
    
    // 改进方式
    function resolve (value) {
      setTimeout(function () {
        callback && callback(value)
      }, 0)
    }
    fn(resolve);
  }

调用promise

 // 实例化promise 回调函数fn执行成功,并执行resolve函数,此时在回调队列里面添加一
 // 一个callback函数,并将resolve的参数传递出去。
 var promise = new Promise(function (resolve) {
    resolve(["3", "aaa"])
 })
// 调用then函数,并执行then回调,将then函数的参数done回调函数赋值给callback,
// 在回调队列里面(之前setTimeout添加进去的回调队列)执行then的回调函数
 promise.then(function (data) {
    console.log("data", data)
 })

但是以上方式写,我们永远都只能执行then中一个回调队列,这显然不健壮。我们结合js设计模式的发布--消息订阅模式,再结合构造函数return this 知识点,稍微改造下:

function Promise(fn){
    //需要一个成功时的回调
    var self = this
    self.deferreds = []; // then函数 回调队列 储存容器
    //一个实例的方法,用来注册异步事件
    self.then = function(onFulfilled){
      self.deferreds.push(onFulfilled)
      console.log("self.deferreds", self.deferreds) 
      // 调用两次then 回调队列会逐个push
      return self // 链式调用then
    }

    // 改进方式
    function resolve (value) {
      setTimeout(function () {
        self.deferreds.forEach(function (deferred) {
           deferred && deferred(value)
        })
      }, 0)
    }
    fn(resolve);
}

调用then函数:

promise.then(function (data) {
    console.log("data", data)
}).then(function (resp) {
    console.log("resp", resp)
})

众所周知,构造函数Promise存在三个互斥状态:pending、fulfilled、rejected。Promise 对象的状态改变,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。

所以:我们改进代码如下:

//略
// 初始化设置状态
self.status = "pending"
//略
// ...
//略
// resolve的时候 将状态置为
self.status = "fulfilled"
//略

调用执行,同样可以得到我们想要的数据。
但是
但是
但是
仅仅加上上面两行代码是不行的,仔细理解加粗的那几个字,再结合我们的代码来看。
当我们调用then函数的时候,往我们then回调队列里面push回调函数,最终不管状态是pending
还是fulfilled,回调队列的函数都是被resolve函数触发的。这样就违背了这句话:只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。
当我们状态改变为fulfilled,我们并没有真正改变状态,每次再重新执行的时候,我们又重新走了一次then添加回调,然后由resolve来触发回调的过程。
所以then函数改进代码如下:

// 当status == "pending"的时候,我们才往then的回调队列push回调函数。
// 否则 直接执行回调函数,不会由resolve来触发then的回调函数执行。
if(self.status == "pending") {
  self.deferreds.push(onFulfilled)
  return self
}
onFulfilled(value)
return self // 链式调用then

所以加入value后,最终代码如下:
基本就实现了链式调用then的一个带有pending 和 fulfilled 状态的Promise
后续会加上reject(), rejected以及最难理解的串行promise。

function Promise(fn){
    //需要一个成功时的回调
    var self = this
    self.deferreds = []; // then函数 回调队列 储存容器
    self.status = "pending"
    self.value = null
    //一个实例的方法,用来注册异步事件
    self.then = function(onFulfilled){
      if(self.status == "pending") {
        self.deferreds.push(onFulfilled)
        return self
      }
      onFulfilled(self.value)
      return self // 链式调用then
    }

    // 改进方式
    function resolve (newValue) {
      setTimeout(function () {
        self.value = newValue
        self.status = "fulfilled"
        self.deferreds.forEach(function (deferred) {
           deferred && deferred(self.value)
        })
      }, 0)
    }
    fn(resolve);
 }
附录参考文献

美团点评

cn博客

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107055.html

相关文章

  • 我了解到的JavaScript异步编程

    摘要:接下来我们看下三类异步编程的实现。事件监听事件发布订阅事件监听是一种非常常见的异步编程模式,它是一种典型的逻辑分离方式,对代码解耦很有用处。 一、 一道面试题 前段时间面试,考察比较多的是js异步编程方面的相关知识点,如今,正好轮到自己分享技术,所以想把js异步编程学习下,做个总结。下面这个demo 概括了大多数面试过程中遇到的问题: for(var i = 0; i < 3; i++...

    RichardXG 评论0 收藏0
  • 30分钟,让你彻底明白Promise原理

    摘要:链式是指在当前达到状态后,即开始进行下一个后邻。在中发现没有指定异步操作失败的回调时,会直接将函数返回的,后同设为状态,如此达成执行后续失败回调的效果。 原文链接 前言 前一阵子记录了promise的一些常规用法,这篇文章再深入一个层次,来分析分析promise的这种规则机制是如何实现的。ps:本文适合已经对promise的用法有所了解的人阅读,如果对其用法还不是太了解,可以移步我的上...

    Profeel 评论0 收藏0
  • Build Your Own Promise

    摘要:意味着代指的操作由于某些原因失败。第一步构造函数有三种状态,。这个构造函数我们可以先这样写创建一个时,首先进行状态初始化。所有的都是的,而并不是所有的对象都是。 一、JavaScript异步编程背景 ​ 从去年ES2015发布至今,已经过去了一年多,ES2015发布的新的语言特性中最为流行的也就莫过于Promise了,Promise使得如今JavaScript异步编程如此轻松惬意...

    susheng 评论0 收藏0
  • Promise原理分析一

    摘要:原理分析一对象用于异步计算。它有两个参数,分别为在成功和失败情况下的回调函数。实现根据当前状态对回调函数进行处理,同时返回一个新的对象,以便链式调用。,注册回调函数到当前的对象中或,立即执行回调函数说明方法只处理被拒绝的情况,并返回一个。 Promise原理分析一 Promise对象用于异步计算。一个Promise对象代表着一个还未完成,但预期将来会完成的操作。 Note: Promi...

    WilsonLiu95 评论0 收藏0
  • 基于vue-cli3.0的项目工程重新构建空白,拿来即用

    摘要:写在前面使用框架开发时,很多人会选择官方提供的脚手架,最新的已经更新到完全无配置,只需下载就能方便的使用构建的项目工程,但基础的并不能满足正常的项目开发,在开发中我们需要根据自己的习惯和业务功能而添加些基础功能。 写在前面 使用vue框架开发时,很多人会选择vue官方提供的cli脚手架,最新的cli已经更新到3.0完全无配置,只需下载就能方便的使用vuecli构建的项目工程,但基础的c...

    xingpingz 评论0 收藏0

发表评论

0条评论

罗志环

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<