chenxd1996

2018-10-09 11:53

简单实现Promise

本文作者:IMWeb chenxd1996 原文出处:IMWeb社区 未经同意,禁止转载

导语:promise相信大家都不陌生,有了promise,配合上async await,再也不用被回调地狱(callback hell) 恶心到。本文我们来简单实现一下Promise。

1. Promise的标准

Promise标准

可以看到promise的规范很详细很明确,只要将规范翻译成代码,就可以实现一个完整的Promise。当然本文只是对Promise的简单实现,一些复杂的情况暂且不考虑。

2. 简单实现Promise

2.1 构造函数

首先写出Promise的构造函数,Promise使用的是发布与订阅模式,调用promise上的then方法将resolve和reject回调分别加入onFulfilledCallback和onRejectedCallback回调函数集合,

然后调用resolve和reject方法触发回调函数集合中函数的执行。

function Promise(fn) {
  var self = this;
  self.status = 'pending'; // Promise初始状态为pending
  self.data = undefined; // Promise的值
  self.onFulfilledCallback = []; // Promise resolve回调函数集合
  self.onRejectedCallback = []; // Promise reject回调函数集合
  fn(resolve, reject); // 执行传进来的函数,传入resolve, reject参数
}

这里再考虑一下resolve函数和reject函数的实现,在构造函数中定义它们。

function Promise(fn) {
  var self = this;
  self.status = 'pending'; // Promise初始状态为pending
  self.data = undefined; // Promise的值
  self.onFulfilledCallback = []; // Promise resolve回调函数集合
  self.onRejectedCallback = []; // Promise reject回调函数集合

  function resolve(value) {
    if (self.status === 'pending') {
      self.status = 'resolved';
      self.data = value;
      for (var i = 0; i < self.onFulfilledCallback.length; i++) {
        self.onFulfilledCallback[i](value);
      }
    }
  }

  function reject(reason) {
    if (self.status === 'pending') {
      self.status = 'rejected';
      self.data = reason;
      for (var i = 0; i < self.onRejectedCallback.length; i++) {
        self.onRejectedCallback[i](reason);
      }
    }
  }

  try {
    fn(resolve, reject); // 执行传进来的函数,传入resolve, reject参数
  } catch (e) {
    reject(e);
  }
}

resolve和reject主要做的就是修改promise的状态,然后执行回调函数,逻辑比较简单。

2.2 then方法

Promise对象有一个then方法,用来注册Promise对象状态确定后的回调。这里需要将then方法定义在Promise的原型上。

Promise.prototype.then = function(onFulfilled, onRejected) {
  var self = this;

  // 根据标准,如果then的参数不是function,则我们需要忽略它
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(v) { return v};
  onRejected = typeof onRejected === 'function' ? onRejected : function(r) { return r };

  // Promise对象存在以下三种状态,对三种状态采用不同处理
  if (self.status === 'resolved') {
    return new Promise(function(resolve, reject) {
      // todo
    });
  }

  if (self.status === 'rejected') {
    return new Promise(function(resolve, reject) {
      // todo
    });
  }

  if (self.status === 'pending') {
    return new Promise(function(resolve, reject) {
      // todo
    });
  }
}

接下来,实现对三种情况的处理

Promise.prototype.then = function(onFulfilled, onRejected) {
  var self = this;

  // 根据标准,如果then的参数不是function,则我们需要忽略它
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(v) { return v};
  onRejected = typeof onRejected === 'function' ? onRejected : function(r) { return r };

  if (self.status === 'resolved') {
    // 这里promise的状态已经确定是resolved,所以调用onResolved
    return new Promise(function(resolve, reject) {
      try {
        // ret是onFulfilled的返回值
        var ret = onFulfilled(self.data);
        if (ret instanceof Promise) {
          // 如果ret是一个promise,则取其值作为新的promise的结果
          ret.then(resolve, reject);
        } else {
          // 否则,以它的返回值作为新的promise的结果
          resolve(ret);
        }
      } catch (e) {
        // 如果出错,以捕获到的错误作为promise2的结果
        reject(e);
      }
    });
  }

  // 这里的逻辑跟前面一样,不再赘述
  if (self.status === 'rejected') {
    return new Promise(function(resolve, reject) {
      try {
        var ret = onRejected(self.data);
        if (ret instanceof Promise) {
          ret.then(resolve, reject);
        } else {
          reject(ret);
        }
      } catch (e) {
        reject(e);
      }
    });
  }

  if (self.status === 'pending') {
    // 如果当前的Promise还处于pending状态,则不能确定调用
    // onResolved还是onRejecte,只能等到Promise状态确定后,
    // 才能确定如何处理
    return new Promise(function(resolve, reject) {
      self.onFulfilledCallback.push(function(value) {
        try {
          var ret = onFulfilled(self.data);
          if (ret instanceof Promise) {
            ret.then(resolve, reject);
          } else {
            resolve(ret);
          }
        } catch (e) {
          reject(e);
        }
      });

      self.onRejectedCallback.push(function(value) {
        try {
          var ret = onRejected(self.data);
          if (ret instanceof Promise) {
            ret.then(resolve, reject);
          } else {
            reject(ret);
          }
        } catch (e) {
          reject(e);
        }
      });
    });
  }
}

// 顺便实现一下catch方法
Promise.prototype.catch = function(onRejected) {
  return this.then(null, onRejected);
}

根据标准,onFulfilled和onRejected函数需要异步执行,所以我们需要稍微再修改一下代码。

function Promise(fn) {
  var self = this;
  self.status = 'pending'; // Promise初始状态为pending
  self.data = undefined; // Promise的值
  self.onFulfilledCallback = []; // Promise resolve回调函数集合
  self.onRejectedCallback = []; // Promise reject回调函数集合

  function resolve(value) {
    if (self.status === 'pending') {
      self.status = 'resolved';
      self.data = value;
      setTimeout(function() {
        for (var i = 0; i < self.onFulfilledCallback.length; i++) {
          self.onFulfilledCallback[i](value);
        }
      });
    }
  }

  function reject(reason) {
    if (self.status === 'pending') {
      self.status = 'rejected';
      self.data = reason;
      setTimeout(function() {
        for (var i = 0; i < self.onRejectedCallback.length; i++) {
          self.onRejectedCallback[i](reason);
        }
      });
    }
  }

  try {
    fn(resolve, reject); // 执行传进来的函数,传入resolve, reject参数
  } catch (e) {
    reject(e);
  }
}

Promise.prototype.then = function(onFulfilled, onRejected) {
  var self = this;

  // 根据标准,如果then的参数不是function,则我们需要忽略它
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(v) { return v};
  onRejected = typeof onRejected === 'function' ? onRejected : function(r) { return r };

  if (self.status === 'resolved') {
    // 这里promise的状态已经确定是resolved,所以调用onResolved
    return new Promise(function(resolve, reject) {
      setTimeout(function() {
        try {
          // ret是onFulfilled的返回值
          var ret = onFulfilled(self.data);
          if (ret instanceof Promise) {
            // 如果ret是一个promise,则取其值作为新的promise的结果
            ret.then(resolve, reject);
          } else {
            // 否则,以它的返回值作为新的promise的结果
            resolve(ret);
          }
        } catch (e) {
          // 如果出错,以捕获到的错误作为promise2的结果
          reject(e);
        }
      });
    });
  }

  // 这里的逻辑跟前面一样,不再赘述
  if (self.status === 'rejected') {
    return new Promise(function(resolve, reject) {
      setTimeout(function() {
        try {
          var ret = onRejected(self.data);
          if (ret instanceof Promise) {
            ret.then(resolve, reject);
          } else {
            reject(ret);
          }
        } catch (e) {
          reject(e);
        }
      });
    });
  }

  if (self.status === 'pending') {
    // 如果当前的Promise还处于pending状态,则不能确定调用
    // onResolved还是onRejecte,只能等到Promise状态确定后,
    // 才能确定如何处理
    return new Promise(function(resolve, reject) {
      self.onFulfilledCallback.push(function(value) {
        setTimeout(function() {
          try {
            var ret = onFulfilled(self.data);
            if (ret instanceof Promise) {
              ret.then(resolve, reject);
            } else {
              resolve(ret);
            }
          } catch (e) {
            reject(e);
          }
        });
      });

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

// 顺便实现一下catch方法
Promise.prototype.catch = function(onRejected) {
  return this.then(null, onRejected);
}

至此,我们已经实现了Promise的基本功能了,让我们来测试一下吧!

const p = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve(1);
  }, 2000);
});

p.then(function(v) {
  console.log(v);
  return 2;
}).then(function(v) {
  console.log(v);
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(3);
    }, 3000);
  });
}).then(function(v) {
  console.log(v);
});

输出:

1
2
3
0条评论

    您需要 注册 一个IMWeb账号或者 才能进行评论。