JavaScript之Promise实现

来源:互联网 发布:node.js能做什么 编辑:程序博客网 时间:2024/06/04 17:47

ES2015提出了Promise,同时基于Promise的异步开发将开发者中回调地狱中解救出来。但在没有原生支持的环境下,需要借助Promise/A+之类的库来实现Promise,今天就来尝试自行实现Promise。

1 基本实现

首先来完成一个Promise类的基本框架:

function Promise(fn) {  var resolveCallback = null  var rejectCallback = null  this.then = function(onResolved, onRejected) {      resolveCallback = onResolved      rejectCallback = onRejected  }  this.resolve = function(value) {      this.resolveCallback(value)  }  this.reject = function(reason) {      this.rejectCallback(reason)  }  fn(this.resolve, this.reject)}

以上便是Promise的基本实现。

2 状态管理

上述的代码存在一个问题,resolve方法会调用多次,所以接下来我们需要接入状态管理。

Promise内部存在3个状态:

  • pending
  • resolved
  • rejected

接下来在现有代码之上,加入状态管理:

function MyPromise(fn) {  let state = 'pending'  var resolveCallback = null  var rejectCallback = null  var childResolve  var childReject  this.then = function(onResolved, onRejected) {      resolveCallback = onResolved      rejectCallback = onRejected  }  this.resolve = function(value) {      if(state === 'pending') {         this.resolveCallback(value)         state = 'resolved'       }   }  this.reject = function(reason) {      if(state === 'pending') {          this.rejectCallback(reason)          state = 'rejected'      }     }  fn(this.resolve, this.reject)}

3 链式调用

上述Promise实现可以完成正常的异步调用,但是却无法实现链式回调,原因在于其then方法没有返回一个新的Promise对象,所以接下来还需要改造then方法,实现链式调用:

  this.then = function(onResolved, onRejected) {      if(state === 'pending') {        resolveCallback = onResolved        rejectCallback = onRejected      }      return new MyPromise((resolve, reject) => {        ......      })  }

光返回一个promise对象还没用,接下来我们来写个demo测试下:

  var demo = new MyPromise((resolve, reject) => {      setTimeout(() => {          resolve('my first promise')      }, 1000)  })  demo.then((msg) => {      console.log(msg)      return 'my second promise'  }).then((msg) => {      console.log(msg)  })

其输出为:

my first promise

事实上,第二个promise对象的resolve reject方法从未被调用过,因而其onResolved onRejected的回调ye就无从调用。所以还必须指定时机调用字promise对象的resolvereject

所以首先需要在创建新promise对象时,记录其resolvereject方法:

function MyPromise() {    ......    var childResolve    var childReject      this.then = function(onResolved, onRejected) {      if(state === 'pending') {        resolveCallback = onResolved        rejectCallback = onRejected      }      return new MyPromise((resolve, reject) => {        childResolve = resolve        childReject = reject      })  }}

接下来还需在resolvereject方法中调用子对象的resolvereject方法,整个Promise完整代码如下:

function MyPromise(fn) {    let state = 'pending'    var resolveCallback = null    var rejectCallback = null    var childResolve = null    var childReject = null    this.then = function(onResolved, onRejected) {        if(state === 'pending') {            resolveCallback = onResolved            rejectCallback = onRejected        }        return new MyPromise((resolve, reject) => {            childResolve = resolve            childReject = reject        })    }    this.resolve = function(value) {        if(state === 'pending') {            if(resolveCallback) {                var ret = resolveCallback(value)                childResolve(ret)                state = 'resolved'             }        }     }    this.reject = function(reason) {        if(state === 'pending') {            if(rejectCallback) {                var ret = rejectCallback(reason)                childReject(ret)                state = 'rejected'            }        }       }    fn(this.resolve, this.reject)  }