Promise的链式调用原理

关于 Promise 的基础概念和使用方法就很少讲了,咱们来聊一聊它的实现原理promise

请你们配合最下方的 Promise/A+ 规范实现代码来阅读浏览器

首先明确一个概念:决议,就是指将 Promise 的状态从 pending 变为 fulfilled/rejected异步

其次 Promise/A+ 规范实现代码中的 setTimeout 能够理解将代码添加到平台的微任务队列中异步执行函数

结合代码描述 Promise 链式调用的整个流程

  1. new Promise(excutor = (resolve, reject) => {}) 后 执行 excutor , 返回一个 Promise 对象 objui

    try {
        excutor(resolve, reject);
      } catch (e) {
        reject(e);
      }
    复制代码
  2. 执行 obj.then(onFulfilled, onRejected)this

    首先判断 onFulfilled 和 onRejected 是不是个函数,若是不是的话就将 onFulfilled 改写成 value => value ,将 onRejected 改写成 reason => { throw reason }spa

    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
     onRejected =
       typeof onRejected === "function"
         ? onRejected
         : reason => {
             throw reason;
           };
    复制代码
  3. obj.then 返回一个 newPromise,它的 excutor 方法与 obj 此时的状态有关prototype

    • 若是 obj 为 pending 状态code

      return newPromise = new Promise((resolve, reject) => {
        that.onFulfilledCallbacks.push(value => {
          try {
            let x = onFulfilled(value);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
        that.onRejectedCallbacks.push(reason => {
          try {
            let x = onRejected(reason);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      })
      复制代码

      then 方法在 obj 处于 pending 状态时 干了这么几件事对象

      1. 建立一个新的 Promise 对象 newPromise 并返回

      2. 执行 newPromise 的 excutor,向 obj 的两个回调队列中添加回调

      3. 向 obj.onFulfilledCallbacks 添加一个成功回调:传入 obj.value 执行 onFulfilled(value) 而后执行 resolvePromise,obj.value 会在 resolve(value) 执行的时候被赋值

      4. 向 obj.onRejectedCallbacks 添加一个失败回调:传入 obj.reason 执行 onRejected(reason) 而后执行 resolvePromise,obj.value 会在 reject(reason) 执行的时候被赋值

    • 若是 obj 已经为 fulfilled 状态

      return newPromise = new Promise((resolve, reject) => {
        setTimeout(() => {
          try {
            let x = onFulfilled(that.value);
            resolvePromise(newPromise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      })
      复制代码

      咱们一样返回了一个新的 Promise 对象,它的 excutor 函数会将 onFulfilled 和 resolvePromise 添加进微任务队列执行,也就是说若是 obj 在已经变为 fulfilled 后再执行 then 方法,就会在同步任务执行完毕后当即执行 then 中传入的 onFulfilled (这个 then 方法中的 onFulfilled 不必再加入到回调队列中,由于它等不到 obj 执行 resolve 的那一天了,Promise 的状态一经决议就不会改变

    • 若是 obj 已经为 rejected 状态,所作处理基本与 fulfilled 状态下相同

  4. 下面咱们主要分析一下 pending 状态,若是 obj 在 pending 状态下执行了 then ,咱们就等待 excutor 中的 resolve 或者 reject 被执行

    • resolve 执行

      接收一个参数 value , 若是 value 也是个 Promise 对象,那么返回 value.then(reslove, reject)

      // 这里是为了保证一个 Promise 决议时的 value 绝对不会是另外一个 Promise
      // 好比 promise1 = new Promise(resolve => resolve(promise2 = new Promise())) 的状况
      // 此时 promise1 决议的时候 value 为 promise2 ,那么就不能继续决议 promise1 了
      // 应该执行 promise2.then(resolve, reject),等待 promise2 的决议而后再决议 promise1
      
      if (value instanceof Promise) {
        return value.then(resolve, reject);
      }
      复制代码

      异步执行接下来的步骤(此处的异步即放置在浏览器的微任务队列中):

      若是 obj.status === 'pending',改状态为 'fulfilled',赋值 obj.value,执行所有 onFulfilledCallbacks 回调,这个时候就会调用咱们在 then 中添加的 onFulfilled 函数

    • reject 执行

      接收一个参数 reason,异步执行接下来的步骤:

      若是 obj.status === 'pending',改状态为 'fulfilled',赋值 obj.reason,执行所有 onRejectedCallbacks 回调,这个时候就会调用咱们在 then 中添加的 onRejected 函数

    • 关于异步执行

      咱们说 Promise.then 是异步的,其实执行 then 方法不是异步的。可是 onFulfilled 和 onRejected 确定是异步执行的,由于 resolve 和 reject 清空回调的时候是异步执行的

  5. 执行 onFulfilled(value) 或者 onRejected(reason) 将返回值赋值给变量 x

    let x = onFulfilled(value);
    复制代码
  6. 执行 resolvePromise(promise2, x, resolve, reject),根据 x 对 promise2 进行决议

    resolvePromise(newPromise, x, resolve, reject);
    复制代码

    注意这里的 promise2 是 then 方法返回的 Promise 对象,resolve 和 reject 是 promise2 的 excutor 中的 resolve 和 reject,也就是说 resolvePromise 的执行过程当中会对 promise2 进行决议

    咱们仔细分析一下 resolvePromise 都作了什么

    首先这个参数 x 就是 onFulfilled(value) 的返回值,若是 onFulfilled 不是个函数,那它就会被改写成 v => v,也就是 x = value

    接下来就是判断 x 究竟是什么

    • 若是 x === promise2,报循环引用的错误

    • 若是 x 是一个 Promise 对象且状态为 pending,那么就执行 x.then 将 onFulfilled 加入 x.onFulfilledCallbacks 回调并等待 x 决议, x 决议后执行回调中的 onFulfilled(x.value) 也就是 x.value => resolvePromise(promise2, x.value, resolve, reject),而上文提到过此时的 x.value 毫不多是一个 Promise 了

      x.then(
        y => {
          resolvePromise(promise2, y, resolve, reject);
        },
        reason => {
          reject(reason);
        }
      );
      复制代码
    • 若是 x 是一个 thenable 对象,处理方式同 pending 状态的 Promise 对象,这里使用一个 called 锁来避免 thenable.then 屡次调用传入的 onFulfilled/onRejected

    • 若是 x 是一个 Promise 对象且状态不为 pending,因此 x.value 或者 x.reason 必会存在一个,此时执行 x.then(resolve, reject),直接决议 promise2 ,即执行 resolve(x.value) 或者 reject(x.reason)

    • 若是 x 是一个普通的函数/对象,或者其余数据类型,则 resolve(x)

从新梳理一下链式调用的流程

  1. promise1 = new Promise(excutor = (resolve, reject) => { ... }) 中的 excutor 是当即执行的,但最后执行 resolve 多是在异步操做中

  2. promise1.then 会给 promise1 添加回调,而后返回一个新的 promise2,这个新的 promise2 的决议依靠以前回调中的 resolvePromise 方法

  3. promise1 决议后会执行回调,首先执行 then 中传入的 onFulfilled(promise1.value),赋值给变量 x,再执行 resolvePromise(promise2, x, promise2Resolve, promise2Reject)

  4. 若是 x 是个已决议的 Promise 或者普通的数据类型,那么就能够 promise2Resolve(x) 决议 promise2

  5. 若是 x 是个 pending 状态的 promise 或者 thenable 对象,那么执行 x.then ,将 resolvePromise 放入 x 的成功回调队列,等待 x 决议后将 x.value 成功赋值,而后执行 resolvePromise(promise2, x.value, promise2Resolve, promise2Reject)

  6. 在此期间若是执行了 promise2.then 就新建一个 promise3 并返回 ,将新传入的 onFulfilled(promise2.value) 和针对 promise3 的 resolvePromise 传入 promise2 的成功回调队列中,等待 promise2 的决议

  7. promise3.then 同上,就此实现了链式调用

链式调用的前后顺序

promise1 决议后才会决议 promise2 ,由于 promise2 的决议方法要在 promise1 的成功回调里执行

链式调用的透传

若是 promise1.then 中传入的的 onFulfilled 不是个函数,那么 onFulfilled 会在 then 中被改写成 value => value,这样就能够将 promise1.value 传递给 promise2 的 resolvePromise 帮助它决议。若是刚好 value 不是一个 pending 状态的 Promise 或者 thenable 对象,那么 promise2 会直接决议,而后 promise1.value 会被赋值给 promise2.value 进而传递给 promise3,这就是所谓的透传

思考

若是 promise2.then 的 onFulfilled 反回了一个新的 PromiseA,那么 promise2 将直接取这个 PromiseA 的状态和值为己用,这发生在 resolvePromise 中;

若是 PromiseA 的 resolve 时传入的 value 是一个新的 PromiseB,那么 PromiseA 也会直接取这个 PromiseB 的状态和值为己用,这发生在 resolve 中;

也就是说,咱们能够经过在 onFulfilled 时返回一个 newPromise,或者 resolve 时传入一个 newPromise,再执行 newPromise.then(resolve, reject) 来实现一个 Promise 决议的挂起(后置),直至 newPromise 决议。

Promise/A+ 规范实现

const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

function Promise(excutor) {
  let that = this; 
  that.status = PENDING;
  that.value = undefined;
  that.reason = undefined;
  that.onFulfilledCallbacks = [];
  that.onRejectedCallbacks = [];

  function resolve(value) {
    
    if (value instanceof Promise) {
      return value.then(resolve, reject);
    }

    setTimeout(() => {
      if (that.status === PENDING) {
        that.status = FULFILLED;
        that.value = value;
        that.onFulfilledCallbacks.forEach(cb => cb(that.value));
      }
    });
  }

  function reject(reason) {
    setTimeout(() => {
      if (that.status === PENDING) {
        that.status = REJECTED;
        that.reason = reason;
        that.onRejectedCallbacks.forEach(cb => cb(that.reason));
      }
    });
  }

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

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError("Chaining cycle detected for promise!"));
  }

  let called = false;
  if (x instanceof Promise) {
    if (x.status === PENDING) {
      x.then(
        y => {
          resolvePromise(promise2, y, resolve, reject);
        },
        reason => {
          reject(reason);
        }
      );
    } else {
      x.then(resolve, reject);
    }
  } else if (x != null && (typeof x === "object" || typeof x === "function")) {
    try {
      let then = x.then;
      if (typeof then === "function") {
        then.call(
          x,
          y => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          reason => {
            if (called) return;
            called = true;
            reject(reason);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}

Promise.prototype.then = function(onFulfilled, onRejected) {
  const that = this;
  let newPromise;
  onFulfilled =
    typeof onFulfilled === "function" ? onFulfilled : value => value;
  onRejected =
    typeof onRejected === "function"
      ? onRejected
      : reason => {
          throw reason;
        };

  if (that.status === FULFILLED) {
    return (newPromise = new Promise((resolve, reject) => {
      setTimeout(() => {
        try {
          let x = onFulfilled(that.value);
          resolvePromise(newPromise, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
    }));
  }

  if (that.status === REJECTED) {
    return (newPromise = new Promise((resolve, reject) => {
      setTimeout(() => {
        try {
          let x = onRejected(that.reason);
          resolvePromise(newPromise, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
    }));
  }

  if (that.status === PENDING) {
    return (newPromise = new Promise((resolve, reject) => {
      that.onFulfilledCallbacks.push(value => {
        try {
          let x = onFulfilled(value);
          resolvePromise(newPromise, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
      that.onRejectedCallbacks.push(reason => {
        try {
          let x = onRejected(reason);
          resolvePromise(newPromise, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
    }));
  }
};
复制代码
相关文章
相关标签/搜索