likes
comments
collection
share

彻底搞懂Promise原理

作者站长头像
站长
· 阅读数 13

一、先讲一下promise的规范:

Promise A+规范是 Promise 所遵循的标准,由Promises/A+组织提出并维护,主要规定了 Promise 的行为和接口,以确保 Promise 的可靠性和可互操作性。

以下是 Promise A+ 规范的主要内容:

1. Promise 状态

Promise 状态分为三种:pending(等待态)、fulfilled(成功态)和 rejected(失败态)。状态的变更只能是从 pending 转换到 fulfilled 或 rejected,并且变更后不能再次改变。

2. then 方法

Promise 实例必须提供一个 then 方法,用于处理 Promise 的状态变更。then 方法可以接收两个参数:onFulfilled 和 onRejected 分别表示在 Promise 状态变为 fulfilled 和 rejected 时需要执行的回调函数。then 方法返回一个新的 Promise 实例。

3. 回调执行

当 Promise 状态变为 fulfilled 后,必须按照 then 方法注册回调的顺序依次执行所有回调函数;当状态变为 rejected 后,也必须按照注册顺序依次执行所有 rejected 回调。如果某个回调不存在,则忽略之。

4. 异步执行

Promise 的 then 方法必须异步执行(即在本轮事件循环结束之后),且应该优先采用 microtask 队列而非 macrotask 队列执行。

5. then 方法链式调用

Promise 的 then 方法应该支持链式调用,即 then 方法必须返回一个新的 Promise 实例,并在上面注册回调函数。

6. 值穿透

Promise.then 调用传递的值可以是简单的常量值或一个新的 Promise 对象,甚至可以是出现 thenable 表示合法的对象,这样的话必须在线程安全的情况下处理这个对象的值。

以上就是 Promise A+ 规范的内容,目的是统一各种 Promise 实现方式,使其具有互操作性。

总结来说就是:

  1. new Promise时需要传递一个executor执行器,执行器会立刻执行;
  2. 执行器中传递了两个参数 resolve成功的函数 他调用时可以传一个值 值可以是任何值 reject失败的函数 他调用时可以传一个值 值可以是任何值;
  3. 只能从pending态转到成功或者失败;
  4. promise实例,每个实例都有一个then方法,这个方法传递两个参数,一个是成功另一个是失败;
  5. 如果调用then时 发现已经成功了 会让成功函数执行并且把成功的内容当作参数传递到函数中;
  6. promise 中可以同一个实例then多次,如果状态是pending 需要将函数存放起来 等待状态确定后 在依次将对应的函数执行 (发布订阅);
  7. 如果类执行时出现了异常 那就变成失败态。

完整实现代码

function Promise(executor) {
  let self = this;
  self.status = 'pending';
  self.value = undefined;
  self.reason = undefined;
  self.onResolved = [];
  self.onRejected = [];
  function resolve(value) {
    if (self.status === 'pending') {
      self.value = value;
      self.status = 'resolved';
      self.onResolved.forEach(fn => fn());
    }
  }
  function reject(reason) {
    if (self.status === 'pending') {
      self.reason = reason;
      self.status = 'rejected';
      self.onRejected.forEach(fn => fn());
    }
  }
  try {
    executor(resolve, reject);
  } catch (e) {
    reject(e);
  }
}
// 解析不同的promise实现
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('循环引用'));
  }
  let called;
  if (x != null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      let then = x.then; // 如何判断是promise 就判断又没then方法 
      if (typeof then === 'function') {
        then.call(x, (y) => {
          if (called) return;
          called = true;
          resolvePromise(promise2, y, resolve, reject);
        }, (e) => {
          if (called) return;
          called = true;
          reject(e);
        });
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}
Promise.prototype.then = function (onfulfilled, onrejected) {
  onfulfilled = typeof onfulfilled == 'function' ? onfulfilled : val => val;
  onrejected = typeof onrejected === 'function' ? onrejected : err => {
    throw err;
  }
  let self = this;

  let promise2;
  promise2 = new Promise((resolve, reject) => {
    if (self.status === 'resolved') {
      setTimeout(() => { // 目的是为了实现异步
        try {
          let x = onfulfilled(self.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      }, 0);
    }
    if (self.status === 'rejected') {
      setTimeout(() => {
        try {
          let x = onrejected(self.reason);
          resolvePromise(promise2, x, resolve, reject); // 解析x 和 promise2的关系
        } catch (e) {
          reject(e);
        }
      }, 0);
    }
    if (self.status === 'pending') {
      self.onResolved.push(function () {
        setTimeout(() => {
          try {
            let x = onfulfilled(self.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      });
      self.onRejected.push(function () {
        setTimeout(() => {
          try {
            let x = onrejected(self.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      });
    }
  })
  return promise2;
}
Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    let results = []; let i = 0;
    function processData(index, data) {
      results[index] = data; // let arr = []  arr[2] = 100
      if (++i === promises.length) {
        resolve(results);
      }
    }
    for (let i = 0; i < promises.length; i++) {
      let p = promises[i];
      p.then((data) => { // 成功后把结果和当前索引 关联起来
        processData(i, data);
      }, reject);
    }
  })
}
Promise.race = function (promises) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      let p = promises[i];
      p.then(resolve, reject);
    }
  })
}
Promise.prototype.catch = function (onrejected) {
  return this.then(null, onrejected)
}
Promise.reject = function (reason) {
  return new Promise((resolve, reject) => {
    reject(reason)
  })
}
Promise.resolve = function (value) {
  return new Promise((resolve, reject) => {
    resolve(value);
  })
}

module.exports = Promise