Promise A+规范简单实践

2018-08-20

前言

JS是单线程的。有异步编程需求时,我们通常使用:


本文介绍Promise。Promise是一个规范,最早在社区中被提出和实现,使得链式回调的代码更加优雅。后来ES6提供了Promise对象,把其写进语言规范之中。不同的平台也有自己的实现,如Node的q模块和co,Es7的async、await等等。当然,也可以自己实现一个Promise库。


规范

Promise是一个对象或函数,必须含有then方法,提供onFulfilled和onRejected两个入参。Promise是异步的,执行成功时调用onFulfilled,返回终值(eventual
 value);失败调用onRejected,返回据因(reason)。

Promise.then(onFulfilled, onRejected)

一个Promise必定处于三种状态的其中一种:等待(Pending)、完成(Fulfilled)和失败(Rejected)。Pending可以转化成其余两种状态,而其余两种状态不能迁移至其他任何状态。如下图:

Promise状态图

边界情况请参考Promise
   A+规范
,这里不再啰嗦。在规范中,一个Promise库还需要提供resolve、reject、all等方法,都很好理解,关键是看怎么实现,这里也不展开介绍。


实践

下面布置一道题目:实现一个符合Promise A+规范的Promise库,只需实现then方法,半小时内完成。参考答案如下:

let P = function(executor) {
  let self = this;
  self.status = 'pending'; //状态
  self.value = undefined; //终值
  self.reason = undefined; //据因
  self.resolveCB = []; //成功回调
  self.rejectCB = []; //失败回调

  // 执行成功
  function resolve (value) {
    if (self.status == 'pending') {
      self.status = 'fulfilled';
      self.value = value;
      self.resolveCB.map((cb)=>{
        cb(self.value);
      })
    }
  }

  // 执行出错
  function reject (reason) {
    if (self.status == 'pending') {
      self.status = 'rejected';
      self.reason = reason;
      self.rejectCB.map((cb)=>{
        cb(self.reason);
      })
    }   
  }

  try {
    executor(resolve, reject);
  } catch(e) {
    reject(e);
  }
}

// 实现then方法
P.prototype.then = function(onFulfilled, onRejected) {
  let self = this;
  let then;
  if (self.status == 'fulfilled') {
    return then = new P((resolve, reject)=>{
      try {
        let value = onFulfilled(self.value);
        resolve(value);
      } catch(e) {
        reject(e);
      }
    });
  }
  if (self.status == 'rejected') {
    return then = new P((resolve, reject)=>{
      try {
        let reason = onRejected(self.reason);
        resolve(reason);
      } catch(e) {
        reject(e);
      }
    });
  }
  if (self.status == 'pending') {
    then = new P((resolve, reject)=>{
      self.resolveCB.push(function(){
        try {
          let value = onFulfilled(self.value);
          resolve(value);
        } catch(e) {
          reject(e);
        }
      });
      self.rejectCB.push(function(){
        try {
          let reason = onRejected(self.reason);
          resolve(reason);
        } catch(e) {
          reject(e);
        }
      });
    });

    return then;
  }
}

module.exports = P;

这是某大厂面试时遇到的上机题。参考答案只实现了then的链式调用,规范中的其他内容一概没有,也没有考虑边界问题,请勿在生产环境中使用。



本文未经许可禁止转载,如需转载关注微信公众号【工程师加一】并留言。