美文网首页
手写promise

手写promise

作者: yanmingfei | 来源:发表于2019-08-15 21:57 被阅读0次

本章节纯粹是对promise手写实现。如果不了解promise自行了解再来学习本章知识。
promise初体验
首先,看一下

var p1 = new Promise(function(reslove,reject){
  reslove(1)
})

运行原理

它是怎么执行的,以及对应的代码是什么

function Promise(exector){
  exector(function(value){//这个函数对应的就是reslove函数
  },function(reason){//这个函数对应的就是reject函数
  })
}

后面会对exector函数中的reslove函数和reject函数添加许多功能,所以我们可以将它拆开

function Promise(exector){
  function reslove(value){}//这个函数对应的就是reslove函数
  function reject(reason){}//这个函数对应的就是reject函数
  exector(reslove,reject)
}

接下来我们可以打印value和reason的值

function Promise(exector){
  function reslove(value) {
    console.log(value)
  }
  function reject(err) {
    console.log(err)
  }
  exector(reslove,reject)
}

问题

现在这样的问题是,对于异步的处理还是要写到当前这个构造函数中。还是会导致回调地狱。如何解决?Promise ES6的实现都是约定 通过then方法来获取数据 。对构造函数添加then方法。
查看then方法的调用,需要传递两个函数,一个是成功时的调用,一个是失败时的调用。两个方法不会同时执行。

p1.then(function (data) {
  console.log(data);
},function (err) {
  console.log(err);
})

如何实现then方法?

Promise.prototype.then = function(onFulfaild,onRejected){

}

两个方法不会同时执行, 那么如何决策?我们可以根据一个状态来决定,也就是用户在new Promise方法中会调用reslove或者reject方法,在调用这两个方法时候,我们可以将状态值修改为约定的值,然后在then方法中根据它们的状态来进行区分到底谁需要执行。
约定状态fulfaild和rejected两个状态,当用户调用reslove方法时将状态改为fulfailed,同样的在then方法中根据这个状态为fulfailed来执行onFulfailed方法。
当用户调用reject方法时将状态改为rejected,同样的在then方法中根据这个状态为rejected来执行onRejected方法。

function Promise(exector) {
  var that = this;
  this.status = 'pending'
  this.value = undefined;
  this.reason = undefined;
  function reslove(value) {
    console.log(value)
    that.value = value;
    that.status = 'fulfailed'
  }
  function reject(err) {
    console.log(err)
    that.reason = err;
    that.status = 'rejected'
  }
  exector(reslove, reject)
}

Promise.prototype.then = function (onFulfaild, onRejected) {
  if (this.status === 'fulfailed') {
    onFulfaild(this.value)
  }
  if (this.status === 'rejected') {
    onRejected(this.reason)
  }
}

同样的将new Promise中执行的reslove或者reject方法中传的值,也记录到Promise这个构造函数身上。执行reslove时,对应的this.value值进行修改,在then方法中,执行onFulfailed方法时传递的是成功时的值即this.value。
执行reject函数时对应的this.reason进行修改,在then方法中,执行onRejected方法时传递的是失败时的值即this.reason。

问题

将new Promise中的方法进行修改,我们改写为异步,查看一下效果

var p1 = new Promise(function (reslove,reject) {
  setTimeout(function () {
    reslove('这是reslove方法执行')
  },1000)
})
p1.then(function (data) {
  console.log('成功调用'+data);
},function (err) {
  console.log('失败调用'+err);
})

最终不会打印任何的结果。原因是因为什么?new Promise方法是同步的,不过exector方法执行中有异步,而修改状态是等到异步完成才会修改,then方法中是同步,它在执行时候异步还没有执行完毕,那么这时的status一直是 pending。那么条件判断中没有一个是成功的,所以then中的onFulfaild和onRejected方法都没有执行。

思考

这时候我们可以考虑订阅发布者模式。当 reslove方法执行完毕或者当rejected执行完毕时,我们再将对应的功能执行。
当为异步时,then方法中获取的status一直是pending。在这时,我们可以将它们对应的方法存放在一个数组中。当异步中的reslove或者reject方法执行时,对数组循环,全部执行。即可。

function Promise(exector) {
  var that = this;
  this.status = 'pending'
  this.value = undefined;
  this.reason = undefined;
  this.onFulfiledCallbacks =[];
  this.onRejectedCallbacks = [];
  function reslove(value) {
    that.value = value;
    that.status = 'fulfailed'
    that.onFulfiledCallbacks.forEach(fn=>{fn()})
  }
  function reject(err) {
    that.reason = err;
    that.status = 'rejected'
    that.onRejectedCallbacks.forEach(fn=>{fn()})
  }
  exector(reslove, reject)
}

Promise.prototype.then = function (onFulfaild, onRejected) {
  var that = this;
  if (this.status === 'fulfailed') {
   onFulfaild(that.value)
  }
  if (this.status === 'rejected') {
    onRejected(that.reason)
  }
  if(this.status === 'pending'){
    this.onFulfiledCallbacks.push(()=>{onFulfaild(that.value)})
    this.onRejectedCallbacks.push(()=>{onRejected(that.reason)})
  }
}

状态统一

执行reslove或者reject方法后这两者之间不可以修改状态。我们可以再添加判断。也就是当状态为初始状态pending时才可以执行reslove或者reject,其它状态时,这两个方法不会再执行。

 function reslove(value) {
   if(that.status === 'pending'){
      that.value = value;
    that.status = 'fulfailed'
  }
    that.onFulfiledCallbacks.forEach(fn=>{fn()})
  }
  function reject(err) {
   if(that.status === 'pending'){
      that.reason = err;
      that.status = 'rejected'
   }
    that.onRejectedCallbacks.forEach(fn=>{fn()})
  }
  exector(reslove, reject)
}

链式编程(简易版)

希望有then之后,还可以继续使用then。那么我们考虑一下,有的同学会觉得直接return this就可以了,不过在这里面,我们要明白一点,then是对promise这个实例才有用。return this确实返回的是当前的实例对象,但是当前实例完成以后状态已经更新,而不再是pending,所以reject和reslove函数就不会再次触发。

解决

在then方法中,可以尝试执行代码时候我们先对其实现生成一次promise实例,然后再将新的实例返回。每次then调用时产生的都是新的promise实例,这样的话,所有的状态都是pending开始,就可以再次执行reslove方法。

Promise.prototype.then = function (onFulfaild, onRejected) {
  var that = this;
  let promise2;
  promise2 = new Promise(function (reslove,reject) {
    if (that.status === 'fulfailed') {
      let x = onFulfaild(that.value)
      reslove(x)
    }
    if (that.status === 'rejected') {
      let x = onRejected(that.reason)
      resolve(x)
    }
    if(that.status === 'pending'){
      that.onFulfiledCallbacks.push(()=>{
        let x = onFulfaild(that.value)
        reslove(x)
      })
      that.onRejectedCallbacks.push(()=>{
        let x = onRejected(that.reason)
        reslove(x)

      })
    }
  })
  return promise2;
}

解释,这里每次不论reslove或者reject方法执行完成之后,都可能有结果。结果可能是普通值,我们这里的代码实现的仅仅是返回一个普通值。后面考虑更多的值,函数或者promise实例等。

完善代码

执行reslove或者reject函数时,可能会报错。应该对其抛出异常,而且通过reject来抛出。

Promise.prototype.then = function (onFulfaild, onRejected) {
  var that = this;
  let promise2;
  promise2 = new Promise(function (reslove,reject) {
    if (that.status === 'fulfailed') {
      try{
        let x = onFulfaild(that.value)
        reslove(x)
      }
      catch (e) {
        reject(e)
      }
    }
    if (that.status === 'rejected') {
      try{
        let x = onRejected(that.reason)
        resolve(x)
      }catch (e) {
        reject(e)
      }
    }
    if(that.status === 'pending'){
      that.onFulfiledCallbacks.push(()=>{
        try{
          let x = onFulfaild(that.value)
          reslove(x)
        }catch (e) {
          reject(e)
        }
      })
      that.onRejectedCallbacks.push(()=>{
        try{
          let x = onRejected(that.reason)
          reslove(x)
        }catch (e) {
          reject(e)
        }
      })
    }
  })
  return promise2;
}

其实学到这里,应该就可以够面试了,如果你还想对源码有更高的要求,那么还要继续往下学习。

相关文章

  • 手写Promise

    手写 Promise 我们会通过手写一个符合 Promise/A+ 规范的 Promise 来深入理解它,并且手写...

  • 手写 Promise 系列 --- 3

    在前两篇(手写 Promise 系列 --- 1)和(手写 Promise 系列 ---2) 中,达成了3个目标 ...

  • 手写Promise

    $ 正常的promise用法   $ 手写的Promise   # 测试可行性

  • 手写promise

    手写promise 带大家手写一个 promis。在手写之前我会先简单介绍一下为什么要使用promise、prom...

  • 纯手写实现自己的nodejs promise 库

    纯手写实现自己的nodejs promise 库什么是Promise?promise 链Async/Await后续...

  • 手写基础 promise

    1. 前言 玩下吧 手写 promise,看看能写成啥样 2. promise 基础结构 3. 手写`promi...

  • 手写 Promise

    一、Promise 是一个异步操作返回的对象,用来传递异步操作的消息。 Promise 介绍和使用详见: 认识并使...

  • 手写Promise

  • 手写Promise

    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。 这篇博客有关于P...

  • 手写promise

    本章节纯粹是对promise手写实现。如果不了解promise自行了解再来学习本章知识。promise初体验首先,...

网友评论

      本文标题:手写promise

      本文链接:https://www.haomeiwen.com/subject/denajctx.html