PromisesA+源码解析(一)

39 阅读3分钟

什么是Promise?

MDN描述是: 一个 Promise 对象代表一个在这个 promise 被创建出来时不一定已知值的代理。它让你能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者。

一个 Promise 必然处于以下几种状态之一:

  • 待定(pending) :初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled) :意味着操作成功完成。
  • 已拒绝(rejected) :意味着操作失败。

对于Promise,我觉得更像一个机器人,需要开关、命令 才可以让Promise这个机器人执行我们想要的结果。而在初始化Promise的时候,需要传入一个执行器excutor,这个就类似一个遥控器,让我们可以改变机器人的状态,执行器需要传入两个参数,一个是成功的回调--resolve,就是让机器人状态改为fulfilled,另一个就是失败的回调--reject,让机器人的状态改为rejected。然后我们需要在then(就是Promise里面的一个函数)中给机器人下命令,这样当机器人状态由一开始的pending转变为resolve或者reject,这其中,状态只能改变一次,就是pending转变resolve或者reject这两个状态其中。而且这状态只能改变一次,总不能一直按开关,这样机器人不得死机。就好像有人一直叫你,向左向右。会昏头转向。

然后,then第一个参数就是机器人启动后要做的事情-就是成功的回调,然后第二个参数就是机器人停止后要做的事情--就是失败后的处理。

实现一个简单的Promise

看完上面那个,对Promise应该有个基本的认识。现在让我们写一个Promise的Demo。

思路:

打算用Es6中class的语法来实现。因为Promise是一个机器人,需要一个执行器来给我们按开关来改变机器人的状态,所以需要Promise的状态:status,这个值当前默认是PENDING,说明当前这个机器人是处于准备状态。 然后,执行器中有两个按钮--resolve、reject,所以得要有两个函数resolve、reject,用于改变当前的状态statusFULLFILLED或者REJECTED,然后还有当按下按钮,需要告诉机器人的信息,启动时的参数为value,关闭时的参数为reason,这样才好知道是怎么回事。

最后,肯定是需要告诉机器人要做什么命令,这时候就得定义一个then函数,传递给机器人,当我按下开关的时候要执行的命令,这时候我们肯定得传两个命令,启动后或者遇到异常后该怎么办--onFufilledonRejected(这两个都是成功或者失败的回调函数)。这样一个简单的Promise就完成了。

代码:


class MyPromise {
  constructor(executor) {
    this.value = undefined;
    this.reason = undefined;
    this.status = PENGDING;
    const resolve = value => {
      this.value = value;
      this.status = FULLFILLED;
    }
    const reject = reason => {
      this.reason = reason;
      this.status = REJECTED;
    }
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFufilled, onRejected) {
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.status === FULLFILLED) {
        setTimeout(() => {
          try {
            onFufilled(this.value);
          } catch (reason) {
            reject(reason);
          }
        }, 0)
      }

      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            onRejected(this.reason);
          } catch (reason) {
            reject(reason);
          }
        }, 0)
      }
    })
  }

  catch (errorCallback) {
    return this.then(null, errorCallback);
  }
}

module.exports = MyPromise;