用es5实现es6的promise,完全搞懂promise的原理

1.promise的含义

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最先提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。git

所谓Promise,简单说就是一个容器,里面保存着某个将来才会结束的事件(一般是一个异步操做)的结果。从语法上说,Promise 是一个对象,从它能够获取异步操做的消息。Promise 提供统一的 API,各类异步操做均可以用一样的方法进行处理。github

Promise对象有如下两个特色。编程

(1)对象的状态不受外界影响。Promise对象表明一个异步操做,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操做的结果,能够决定当前是哪种状态,任何其余操做都没法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其余手段没法改变。数组

(2)一旦状态改变,就不会再变,任什么时候候均可以获得这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种状况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。若是改变已经发生了,你再对Promise对象添加回调函数,也会当即获得这个结果。这与事件(Event)彻底不一样,事件的特色是,若是你错过了它,再去监听,是得不到结果的。promise

有了Promise对象,就能够将异步操做以同步操做的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操做更加容易。bash

Promise也有一些缺点。首先,没法取消Promise,一旦新建它就会当即执行,没法中途取消。其次,若是不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,没法得知目前进展到哪个阶段(刚刚开始仍是即将完成)。框架

2.小试promise用法:

Promise构造函数接受一个函数做为参数,该函数的两个参数分别是resolvereject。它们是两个函数,由 JavaScript 引擎提供,不用本身部署。异步

resolve函数的做用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操做成功时调用,并将异步操做的结果,做为参数传递出去;reject函数的做用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操做失败时调用,并将异步操做报出的错误,做为参数传递出去。异步编程


var p=new Promise(function(resolve,rejcet){
    setTimeout(function(){
        if(true){
            //异步操做成功
            resolve('success');
        }else{
            //异步操做失败
            rejcet('failure');
        }
    },1000);
});
p.then(function(value){
    //成功的回调
    console.log(value);
},function(error){
    //失败的回调
    console.log(error);
});复制代码

从demo中能够看到,在ES6中Promise对象是一个构造函数,用来生成Promise实例。而且Promise实例生成之后,能够用then方法分别指定resolved状态和rejected状态的回调函数。函数

3.手写一个promise,完全掌握它的原理

首先,咱们先搭建好代码的骨架:

function Promise(callback) {
  var self = this //promise实例
  self.status = 'PENDING' // Promise当前的状态
  self.data = undefined  // Promise的值
  self.onResolvedCallback = [] // Promise resolve时的回调函数集
  self.onRejectedCallback = [] // Promise reject时的回调函数集
  callback(resolve, reject) // 执行executor并传入相应的参数

  function resolve(value){

  }
  function reject(error){

  }
}
// 添加咱们的then方法
Promise.prototype.then=function(){

}复制代码

咱们先建立一个Promise构造函数,并传入一个回调函数callback,callback里面传入两个函数做为参数,一个是resove,一个是reject。并在Promise的原型上加入咱们的then方法。框架搭好了,接下来咱们来一点点的完善框架里面的内容,能够这么说,把resolve,reject和then补充完,基本能够说就是把Promise完成了。

而后紧接着,咱们完善一下resolve和reject:

function Promise(callback) {
  var self = this
  self.status = 'PENDING' // Promise当前的状态
  self.data = undefined  // Promise的值
  self.onResolvedCallback = [] // Promise resolve时的回调函数集
  self.onRejectedCallback = [] // Promise reject时的回调函数集
  callback(resolve, reject) // 执行executor并传入相应的参数

  function resolve(value){
      if(self.status=='PENDING'){
          self.status=='FULFILLED';
          self.data=value;
          // 依次执行成功以后的函数栈
          for(var i = 0; i < self.onResolvedCallback.length; i++) {
            self.onResolvedCallback[i](value)
          }
      }
  }

  function rejecte(error){
    if (self.status === 'PENDING') {
       self.status = 'REJECTED'
       self.data = error;
       // 依次执行失败以后的函数栈
       for(var i = 0; i < self.onRejectedCallback.length; i++) {
           self.onRejectedCallback[i](error)
        }
    }
  }
}复制代码

接下来咱们实现咱们的then方法:

then方法是Promise的核心,所以这里会花比较大的篇幅去介绍then:

一个promise的then接受两个参数:

promise.then(onFulfilled, onRejected)复制代码

onFulfilledonRejected 都是可选参数。

  • 若是 onFulfilled 不是函数,其必须被忽略
  • 若是 onRejected 不是函数,其必须被忽略

onFulfilled 特性

若是 onFulfilled 是函数:

  • promise 执行结束后其必须被调用,其第一个参数为 promise 的终值,也就是resolve传过来的值
  • promise 执行结束前其不可被调用
  • 其调用次数不可超过一次

onRejected 特性

若是 onRejected 是函数:

  • promise 被拒绝执行后其必须被调用,其第一个参数为 promise 的据因,也就是reject传过来的值
  • promise 被拒绝执行前其不可被调用
  • 其调用次数不可超过一次

调用时机

onFulfilledonRejected 只有在执行环境堆栈仅包含平台代码时才可被调用(平台代码指引擎、环境以及 promise 的实施代码)

调用要求

onFulfilledonRejected 必须被做为函数调用(即没有 this 值,在严格模式(strict) 中,函数 this 的值为 undefined ;在非严格模式中其为全局对象。)

屡次调用

then 方法能够被同一个 promise 调用屡次

  • promise 成功执行时,全部 onFulfilled 需按照其注册顺序依次回调
  • promise 被拒绝执行时,全部的 onRejected 需按照其注册顺序依次回调

返回

then 方法必须返回一个 promise 对象

promise2 = promise1.then(onFulfilled, onRejected);复制代码
  • 若是 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程[[Resolve]](promise2, x)
  • 若是 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
  • 若是 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
  • 若是 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因

不论 promise1 被 reject 仍是被 resolve 时 promise2 都会被 resolve,只有出现异常时才会被 rejected

每一个Promise对象均可以在其上屡次调用then方法,而每次调用then返回的Promise的状态取决于那一次调用then时传入参数的返回值,因此then不能返回this,由于then每次返回的Promise的结果都有可能不一样。

接下来咱们来写咱们的then方法:

Promise.prototype.then = function(onResolved, onRejected) {
  var self = this
  var promise2

  // 根据标准,若是then的参数不是function,则咱们须要忽略它,此处以以下方式处理
  onResolved = typeof onResolved === 'function' ? onResolved : function(value) {}
  onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {}

  if (self.status === 'resolved') {
    // 若是promise1(此处即为this/self)的状态已经肯定而且是resolved,咱们调用onResolved
    // 由于考虑到有可能throw,因此咱们将其包在try/catch块里
    return promise2 = new Promise(function(resolve, reject) {
      try {
        var x = onResolved(self.data)
        if (x instanceof Promise) { // 若是onResolved的返回值是一个Promise对象,直接取它的结果作为promise2的结果
          x.then(resolve, reject)
        }
        resolve(x) // 不然,以它的返回值作为promise2的结果
      } catch (e) {
        reject(e) // 若是出错,以捕获到的错误作为promise2的结果
      }
    })
  }

  // 此处与前一个if块的逻辑几乎相同,区别在于所调用的是onRejected函数,就再也不作过多解释
  if (self.status === 'rejected') {
    return promise2 = new Promise(function(resolve, reject) {
      try {
        var x = onRejected(self.data)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        }
      } catch (e) {
        reject(e)
      }
    })
  }

  if (self.status === 'pending') {
  // 若是当前的Promise还处于pending状态,咱们并不能肯定调用onResolved仍是onRejected,
  // 只能等到Promise的状态肯定后,才能确实如何处理。
  // 因此咱们须要把咱们的**两种状况**的处理逻辑作为callback放入promise1(此处即this/self)的回调数组里
  // 逻辑自己跟第一个if块内的几乎一致,此处不作过多解释
    return promise2 = new Promise(function(resolve, reject) {
      self.onResolvedCallback.push(function(value) {
        try {
          var x = onResolved(self.data)
          if (x instanceof Promise) {
            x.then(resolve, reject)
          }
        } catch (e) {
          reject(e)
        }
      })

      self.onRejectedCallback.push(function(reason) {
        try {
          var x = onRejected(self.data)
          if (x instanceof Promise) {
            x.then(resolve, reject)
          }
        } catch (e) {
          reject(e)
        }
      })
    })
  }
}

// 为了下文方便,咱们顺便实现一个catch方法
Promise.prototype.catch = function(onRejected) {
  return this.then(null, onRejected)
}复制代码

最后附上完整的代码:

Promise.prototype.then = function(onResolved, onRejected) {
  var self = this
  var promise2

  // 根据标准,若是then的参数不是function,则咱们须要忽略它,此处以以下方式处理
  onResolved = typeof onResolved === 'function' ? onResolved : function(value) {}
  onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {}

  if (self.status === 'resolved') {
    // 若是promise1(此处即为this/self)的状态已经肯定而且是resolved,咱们调用onResolved
    // 由于考虑到有可能throw,因此咱们将其包在try/catch块里
    return promise2 = new Promise(function(resolve, reject) {
      try {
        var x = onResolved(self.data)
        if (x instanceof Promise) { // 若是onResolved的返回值是一个Promise对象,直接取它的结果作为promise2的结果
          x.then(resolve, reject)
        }
        resolve(x) // 不然,以它的返回值作为promise2的结果
      } catch (e) {
        reject(e) // 若是出错,以捕获到的错误作为promise2的结果
      }
    })
  }

  // 此处与前一个if块的逻辑几乎相同,区别在于所调用的是onRejected函数,就再也不作过多解释
  if (self.status === 'rejected') {
    return promise2 = new Promise(function(resolve, reject) {
      try {
        var x = onRejected(self.data)
        if (x instanceof Promise) {
          x.then(resolve, reject)
        }
      } catch (e) {
        reject(e)
      }
    })
  }

  if (self.status === 'pending') {
  // 若是当前的Promise还处于pending状态,咱们并不能肯定调用onResolved仍是onRejected,
  // 只能等到Promise的状态肯定后,才能确实如何处理。
  // 因此咱们须要把咱们的**两种状况**的处理逻辑作为callback放入promise1(此处即this/self)的回调数组里
  // 逻辑自己跟第一个if块内的几乎一致,此处不作过多解释
    return promise2 = new Promise(function(resolve, reject) {
      self.onResolvedCallback.push(function(value) {
        try {
          var x = onResolved(self.data)
          if (x instanceof Promise) {
            x.then(resolve, reject)
          }
        } catch (e) {
          reject(e)
        }
      })

      self.onRejectedCallback.push(function(reason) {
        try {
          var x = onRejected(self.data)
          if (x instanceof Promise) {
            x.then(resolve, reject)
          }
        } catch (e) {
          reject(e)
        }
      })
    })
  }
}

// 为了下文方便,咱们顺便实现一个catch方法
Promise.prototype.catch = function(onRejected) {
  return this.then(null, onRejected)
}复制代码
相关文章
相关标签/搜索