为了账号安全,请及时绑定邮箱和手机立即绑定

简单实现 ES6 Promise

标签:
JavaScript
最近在使用ES6,所以手动实现了一个简单的ES6 Promise对象来玩玩(如果有错误的地方,希望大家能够不吝赐教)

一个promise对象接收的是一个callback
这个callback接收两个参数(resolve,reject)
当我们在callback内执行resolvereject的时候,就会调用Promise内定义的 resolvereject函数
然后,resolvereject函数会改变Promise的状态
所以它应该是像下面这样的

function MyPromise(callback) {  // 保存this值
  var self = this
  // 记录状态null为pending,true为resolved,false为reject
  var state = null
  // 记录resolve的参数
  var param = null

  // 执行传入的callback并改变promise对象状态
  callback(resolve, reject)  // resolve方法
  function resolve(data) {    // 改变状态
    state = true
    param = data
  }  // reject方法
  function reject(err) {
    state = false
    param = err
  }
}

但没有then方法的Promise对象是不完整的(完全没有用)
所以我们需要一个then方法,要记住then方法返回的也是一个promise对象
then方法接收两个可选的参数(onFulfilled, onRejected)(我们可以先忽略可选两个字)
then方法传进来的参数必须是函数,如果不是就要忽略(PromiseA+规范)(我们可以也先忽略这句话)

  this.then = function (onFulfilled, onRejected) {    // 返回一个新的promise对象
    return new self.constructor(function (resolve, reject) {      // then
    })
  }

接下来就是then方法的具体实现了
then方法中onFulfilled, onRejected的返回值会作为新promise的执行结果

onFulfilled, onRejected这两个函数要在promise的状态变为pending或resolved的时候才能分别执行
所以如果promise方法状态为resolvedrejected的话,我们就可以直接在then方法中执行resolve(onFulfilled(param))reject(onRejected(param))

  this.then = function (onFulfilled, onRejected) {    // 返回一个新的promise对象
    return new self.constructor(function (resolve, reject) {       if (state === true) {        // param是promise对象完成后的结果
        resolve(onFulfilled(param))
      } else if (state === false) {
        reject(onRejected(param))
      } else {        // 没有执行完毕,怎么办
      }
    })
  }

但如果promise的状态为pending
由于原始promise的状态我们是无法动态获取的,因此我们就需要在他执行状态改变的时候同时执行onFulfilledonRejected方法
我们可以把这个方法放在原始promise对象的resolvereject方法中执行
因此我们要在promise的对象定义中添加四个参数,分别记录onFulfilledonRejected,以及then方法返回的新promise对象的resolvereject
然后如果执行then方法的时候promise对象的状态为pending的话,就将上述四个参数记录起来

// then方法返回的promise对象的resolve和rejectvar nextResolve = nullvar nextReject = null// 记录then方法的参数,onFulfilled和onRejectedvar asynconFulfilled = nullvar asynconRejected = null//then方法this.then = function (onFulfilled, onRejected) {    // 返回一个新的promise对象
    return new self.constructor(function (resolve, reject) {      if (state === true) {        // param是promise对象完成后的结果
        resolve(onFulfilled(param))
      } else if (state === false) {
        reject(onRejected(param))
      } else {
        nextResolve = resolve
        nextReject = reject
        asynconFulfilled = onFulfilled
        asynconRejected = onRejected
      }
    })
  }

接下来就是原始promise中的resolvereject的重新实现

 // resolve方法
  function resolve(data) {    // 改变状态
    state = true
    param = data
    nextResolve(asynconFulfilled(param))
  }  // reject方法
  function reject(err) {
    state = false
    param = err
    nextReject(asynconRejected(param))
  }

很简单不是吗
我们继续
上述实现我们一直没有考虑一个很重要的情况,如果then方法返回的还是一个promise对象,那么如果我们后边还有then方法的话就要等待前一个then方法中的promise对象的状态从pending变为完成
这要怎么做呢
什么时候可以认为then方法返回的promise对象执行完毕了呢,这里我们就要用到then方法(@_@,边写边用...),
resolve方法为例

var self = this// resolve方法function resolve(data) {  // 记录onFulfilled的执行结果
  let parmise  // 改变状态
  state = true
  param = data  // 执行记录的onFulfilled
  parmise = asynconFulfilled(param)  if(parmise === undefined){    // 如果parmise为undefined,就不能解析parmise.constructor
  } else if (parmise.constructor === self.constructor) {    // 等待传递进来的promise对象执行完毕,然后根据传递进来的promise对象的状态执行resolve或reject
    // 注意,这个param是形参,在then方法的promise中执行
    promise.then(function (param) {
      resolve(param)
    }, function (param) {
      reject(param)
    })
  } else {    // 这个是前边的then返回的不是promise对象的情况
    resolve(promise)
  }
}

前面我们忽略了两点 (then方法接收两个可选的参数(onFulfilled, onRejected)) 和 (then方法传进来的参数必须是函数,如果不是就要忽略)

var self = this// resolve方法function resolve(data) {  // 记录onFulfilled的执行结果
  var parmise  // 改变状态
  state = true
  param = data  // 执行记录的onFulfilled
  // begin--------------
  if (typeof onFulfilled === 'function') {
    promise = onFulfilled(param)    if (promise === undefined) {      // 待补充
    } else if (promise.constructor === self.constructor) {      // 注意,这个param是形参,在then方法的promise中执行
      promise.then(function (param) {
        resolve(param)
      }, function (param) {
        reject(param)
      })
    } else {
      reject(promise)
    }
  } else {    // 如果onFulfilled不是function,忽略,直接resolve或reject
    resolve(param)
  }  // ---------------end}

上面begin到end之间的代码还要在then方法调用,所以我们可以把这段代码抽象为一个函数
resolvereject的原理相同,只要注意如果不是function 的话需要执行reject


onFulfilledonRejected只有在[执行环境]堆栈仅包含平台代码时才可被调用
所以将上述begin-end之间的代码放到seTimeout中执行(浏览器环境)

function resolve(data) {  // 记录onFulfilled的执行结果
  var parmise  // 改变状态
  state = true
  param = data  // 执行记录的onFulfilled
  window.setTimeout(function () {    // begin--------------
    // 上述代码
    // ---------------end
  }, 0)
}

下面是完整代码

// 简单实现ES6 Promisefunction MyPromise(callback) {  // 保存this值
  var self = this
  // 记录状态null为pending,true为resolved,false为reject
  var state = null
  // 记录resolve的参数
  var param = null
  // then方法返回的promise对象的resolve和reject
  var nextResolve = null
  var nextReject = null
  // 记录then方法的参数,onFulfilled和onRejected
  var asynconFulfilled = null
  var asynconRejected = null

  // 执行并改变promise对象状态
  callback(resolve, reject)  // then方法
  this.then = function (onFulfilled, onRejected) {    // 返回一个新的promise对象
    return new self.constructor(function (resolve, reject) {      // 判断异步代码是否执行完毕(是否resolve或reject)
      // 若执行完毕就在then方法中立即执行,否则将四个参数记录下来,等待state就绪后再执行doAsyn*函数
      if (state === true) {
        doAsynconFulfilled(onFulfilled, resolve, reject)
      } else if (state === false) {
        doAsynconRejected(onRejected, resolve, reject)
      } else {
        nextResolve = resolve
        nextReject = reject
        asynconFulfilled = onFulfilled
        asynconRejected = onRejected
      }
    })
  }  // resolve方法
  function resolve(data) {    // 改变状态
    state = true
    param = data    if(nextResolve){
        doAsynconFulfilled(asynconFulfilled, nextResolve, nextReject)
    }
  }  // reject方法
  function reject(err) {
    state = false
    param = err    if(nextReject){
        doAsynconRejected(asynconRejected, nextResolve, nextReject)
    }
  }  // 核心方法(我觉得是)

  function doAsynconFulfilled(onFulfilled, resolve, reject) {      window.setTimeout(function () {        // 判断onFulfilled是否为function,不是则忽略
        if (typeof onFulfilled === 'function') {          // 执行onFulfilled方法获取返回值promise()
          let promise = onFulfilled(param)          // 如果promise为undefined 执行 if
          // 如果promise为MyPromise对象 执行 else if
          // 如果promise为非MyPromise对象 执行 else
          if (promise === undefined) {
            resolve(param)            // 待补充
          } else if (promise.constructor === self.constructor) {            // 等待传递进来的promise对象执行完毕,然后根据传递进来的promise对象的状态执行resolve或reject
            promise.then(function (param) {
              resolve(param)
            }, function (param) {
              reject(param)
            })
          } else {            // 执行then方法返回的对象的resolve
            resolve(promise)
          }
        } else {          // 传递参数
          resolve(param)
        }
      }, 0)
    
  }  function doAsynconRejected(onRejected, resolve, reject) {    window.setTimeout(function () {        if (typeof onRejected === 'function') {          let promise = onRejected(param)          if (promise === undefined) {
            reject(param)            // 待补充
          } else if (promise.constructor === self.constructor) {
            promise.then(function (param) {
              resolve(param)
            }, function (param) {
              reject(param)
            })
          } else {
            reject(promise)
          }
        } else {          // 传递错误信息
          reject(param)
        }
    }, 0)
  }
}// 测试使用var b = function (message) {    return new MyPromise(function (resolve, reject) {        document.body.onclick = function () {
            resolve('click:' + message)
        }
    })
}var a = new MyPromise(function (resolve, reject) {
  resolve(123)
}).then(function (message) {    return b(message)
}).then().then(function (message) {    console.log('final:' + message)
},function (err) {    console.log('final:' + err)
})console.log('window')

完毕!



作者:LitCigar
链接:https://www.jianshu.com/p/69dcb2f415dc

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消