Promise详解二(解读Promise规范+手写Promise)

任何符合promise规范的对象和函数都可以成为Promise。
以下内容参考自promise A plus 规范,地址:https://promisesaplus.com/

基本术语

  1. Promise:是一个具有then方法的对象或函数,其行为符合Promises/A+规范。
  2. thenadble:是一个定义了then方法的对象或函数。
  3. value:指任何JavaScript的合法值(包括undefined,thenable,和promise)。
  4. exception:使用throw抛出的一个值。
  5. reason:说明Promise状态改为rejected的原因。

要求

1. Promise的状态

一个Promise的当前状态必须是一下三种状态中的一种:pending,fullfilled,rejected。

  • 当处于pending状态时,Promise可以转换为fullfilled状态或rejected状态。
  • 当处于fullilled状态时,Promise的状态不能被更改,且必须有一个不可变的值。
  • 当处于rejected状态时,Promise的状态不能被更改,且必须有一个不可变的原因。

2. then方法

Promise必须提供一个then方法,可以查看其当前或最终的值或者原因。
Promise的then方法接收两个可选参数:Promise.then(onFullfilled, onRejected)。

2.1 如果onFullfilled或onRejected不是函数,则需要忽略他们。
2.2 如果onFullfilled是一个函数:

  • Promise的状态变为fullfilled前其不能被调用。
  • Promise的状态变为fullfilled后必须被调用,且接收Promise的结果作为第一个参数。
    最多被调用一次。

2.3 如果onRejected是一个函数:

  • Promise的状态变为rejected前其不能被调用。
  • Promise的状态变为rejected状态后必须被调用,且接收Promise的原因作为第一个参数。
    最多被调用一次。

2.4 当执行上下文堆栈仅包含“platform code”之前,不能调用onFullFilled和onRejected。

这里“platform code”是指引擎、环境和Promise参数函数代码。在实际应用中,这一要求确保onFulfilled和onRejected在调用事件循环后以新的堆栈异步执行。这可以通过“宏任务”机制(如setTimeout或setImmediate)实现,也可以通过“微任务”机制(如MutationObserver或process.nextTick实现。

2.5 onFulfilled 和 onRejected 必须被作为普通函数调⽤(即⾮实例化调⽤,这样函数内部 this ⾮严格模式下指向 window)。
2.6 then ⽅法可以被同⼀个 promise 调⽤多次。

  • 当 promise 成功执⾏时,所有 onFulfilled 需按照其注册顺序依次回调。
  • 当 promise 被拒绝执⾏时,所有的 onRejected 需按照其注册顺序依次回调。

2.7 then ⽅法必须返回⼀个新的 promise 对象: promise2 = promise1.then(onFulfilled, onRejected);

  • 只要 onFulfilled 或者 onRejected 返回⼀个值 x ,promise2 都会进⼊ resolved 状态。
  • 如果 onFulfilled 或者 onRejected 抛出⼀个异常 e ,则 promise2 会进入rejected状态,并返回拒绝原因 e。
  • 如果 onFulfilled 不是函数且 promise1 状态变为fullfilled, promise2 会进入fullfilled状态并返回相同的值。
  • 如果 onRejected 不是函数且 promise1 状态变为rejected, promise2 会进入rejected状态并返回相同的拒绝原因。

3. Promise的解析过程

promise解析过程是一个抽象操作,输入一个promise和一个值,我们将其表示为[[Resolve]](promise,x)。如果x是一个tenable,它试图使promise采用x的状态。否则,它就将x值包装成一个Promise。
3.1 如果promise和x指向同一个对象,Promise将进入rejected状态,并返回一个TypeError作为拒绝原因。
3.2 如果 x 为 promise:

  • 如果 x 处于pending状态, promise 需保持为pending直⾄ x 被执⾏或拒绝。
  • 如果 x 处于fullfilled状态,⽤相同的值执⾏ promise。
  • 如果 x 处于rejected态,⽤相同的拒绝原因拒绝promise。

3.3 如果 x 为对象或函数(不常见):

  • 首先尝试执行x.then,
  • 如果取x.then时抛出错误e,则以e为原因拒绝Promise。
  • 如果then是函数,将x作为函数作用域调用。传递两个回调函数作为参数,第一个叫做resolvePromise,第二个叫做rejectPromise:
    • 如果 resolvePromise 以值 y 为参数被调⽤,则运⾏[[Resolve]](promise,y)。
    • 如果 rejectPromise 以拒绝原因 r 为参数被调⽤,则以拒绝原因 r 拒绝 promise。
    • 如果 resolvePromise 和 rejectPromise 均被调⽤,或者被同⼀参数调⽤了多次,则优先采⽤⾸次调⽤并忽略其他的调⽤。
    • 如果调⽤ then ⽅法抛出了异常 e:
      • 如果 resolvePromise 或 rejectPromise 已经被调⽤,则忽略。
      • 否则以 e 为拒绝原因拒绝 promise。
    • 如果then不是函数,以x为参数将Promise变为fullfilled状态。

3.4 如果 x 不是对象或者函数,以x为参数将Promise变为fullfilled状态(重要且常见)。

------------------------------------------------------------手写Promise来啦---------------------------------------------------------------
------------------------------------------------------------手写Promise来袭---------------------------------------------------------------

class MyPromise {
  constructor(handleFn) {
    // Promise的状态
    this.PromiseState = "pending";
    // Promise的结果
    this.PromiseValue = null;

    // 画重点!!!这两个list是为了将下一个Promise与当前Promise相关联
    this._toNextResolve = [];
    this._toNextReject = [];
    // Promise接收的函数参数
    handleFn(this.triggerResolve.bind(this), this.triggerReject.bind(this));
  }

  // resolve处理
  triggerResolve(data) {
    // 这里使用setTimeout的原因是:确保resolve处理函数在handleFn所处的事件循环后以新的堆栈异步执行。(参见:2.4)
    setTimeout(() => {
      // Promise的状态不是pending时,不能被修改状态。(参见:1)
      if (this.PromiseState !== "pending") return;
      // 修改Promise的状态和值
      this.PromiseState = "fullfilled";
      this.PromiseValue = data;
      this._toNextResolve.forEach(item => item(data));
      this._toNextResolve = [];
    }, 0);
  }

  // reject处理,同上
  triggerReject(data) {
    setTimeout(() => {
      if (this.PromiseState !== "pending") return;
      this.PromiseState = "rejected";
      this.PromiseValue = data;
      this._toNextReject.forEach(item => item(data));
      this._toNextReject = [];
    }, 0);
  }

  // 将多个Promise包装成一个新的Promise实例,并在所有异步操作执行完后执行回调
  static all(list) {
    const result = [];
    let count = 0;
    return new MyPromise(function(resolve, reject) {
      for (let [i, MyPromiseInstance] of list.entries()) {
        MyPromiseInstance.then(
          res => {
            result[i] = res;
            count++;
            if (count === list.length) resolve(result);
          },
          err => {
            reject(err);
          }
        );
      }
    });
  }

  static race(list) {
    return new MyPromise(function(resolve, reject) {
      for (let [i, MyPromiseInstance] of list.entries()) {
        MyPromiseInstance.then(
          res => {
            resolve(res);
          },
          err => {
            reject(err);
          }
        );
      }
    });
  }

  // static resolve(val) {
  //   return new MyPromise(resolve=>resolve(val));
  // }

  // static reject(val) {
  //   return new MyPromise(resolve=>{}, reject=>reject(val));
  // }
}

MyPromise.prototype.then = function(onResolved, onRejected) {
  const { PromiseState, PromiseValue } = this;

  // then方法必须返回一个Promise对象。(参见:2.7)
  return new MyPromise((onNextResolved, onNextRejected) => {
    function onLastFullFilled(val) {
      if (typeof onResolved !== "function") {
        // 如果onResolved不是函数,则需要忽略他。(参见:2.1)
        onNextResolved(val);
      } else {
        const res = onResolved(val);
        if (res && typeof res.then === "function") {
          // 若res 是一个 promise
          res.then(onNextResolved);
        } else {
          // 若res 非 promise,则直接执行下一个 onNextResolved
          onNextResolved(res);
        }
      }
    }
    function onLastRejected(val) {
      if (typeof onRejected !== "function") {
        // 如果onRejected不是函数,则需要忽略他。(参见:2.1)
        onNextRejected(val);
      } else {
        const res = onRejected(val);
        if (res && typeof res.then === "function") {
          // 若res 是一个 promise
          res.then(onNextRejected);
        } else {
          // 若res 非 promise,则直接执行下一个 onNextRejected
          onNextRejected(res);
        }
      }
    }
    switch (PromiseState) {
      case "pending": {
        this._toNextResolve.push(onLastFullFilled);
        this._toNextReject.push(onLastRejected);
        break;
      }
    }
  });
};

const p1 = function() {
  return new MyPromise(function(resolve, reject) {
    setTimeout(function() {
      const random = Math.random() * 10;
      if (random > 5) {
        resolve("已完成1:" + random);
      } else {
        reject("已拒绝1:" + random);
      }
    }, 1000);
  });
};

const p2 = function() {
  return new MyPromise(function(resolve, reject) {
    const random = Math.random() * 10;
    resolve("已完成2:" + random);
  });
};

const p3 = function() {
  return new MyPromise(function(resolve, reject) {
    const random = Math.random() * 10;
    resolve("已完成3:" + random);
  });
};

p1().then(
  res => {
    console.log('then方法:');
    console.log(res);
  },
  err => {
    console.log('then方法:');
    console.log(err);
  }
);

MyPromise.all([p1(), p2(), p3()]).then(
  res => {
    console.log('all方法:');
    console.log(res);
  },
  err => {
    console.log('all方法:');
    console.log(err);
  }
);

MyPromise.race([p1(), p2(), p3()]).then(
  res => {
    console.log('race方法:');
    console.log(res);
  },
  err => {
    console.log('race方法:');
    console.log(err);
  }
);
上一篇:Promise A+ 规范【中文版】


下一篇:promises的深入学习