Es6 - Promise源码分析

79 阅读4分钟
Promise 方法
  • all :成功的时候返回的是一个结果数组,失败的时候则返回最先被reject失败状态的值
  • allthrottle:返回一个结果数组,包含成功、失败
  • any:只要其中的一个 promise 成功,就返回那个已经成功的 promise
  • rance:哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态
  • resolve、 reject
// 定义状态常量
const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";

class MyPromise {
  // executor
  // 1、自执行函数,new MyPromise时立刻执行
  // 2、包含两个参数:resolve和reject函数
  constructor(executor) {
  
    // 状态只能被修改一次
    this.status = PENDING;
    this.value = undefined;
    this.reason = undefined;


    // 存储所有的成功或失败的回调函数
    // new MyPromise() 被多次调用
    //   p1.then().then().then()
    //   p1.then().then().then()
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    // 每次 new 的时候都需要创建自己的 resolve 和 reject 方法
    // 成功回调
    const resolve = (value) => {
      if (this.status == PENDING) {
        this.value = value;
        this.status = FULFILLED;
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    }
    // 失败回调
    const reject = (value) => {
      if (this.status == PENDING) {
        this.reason = value;
        this.status = REJECTED;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    }

    // new Promise时 执行 executor 函数
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error)
    }

  }

  // 每个 then 都返回一个新的promie对象,进行链式调用
  then(onFulfilled, onRejected) {
    // 解决穿透问题:
    // 1、如果 onFulfilled 或 onRejected 为空,默认给一个函数
    // 2、例如:promise2.then().then().then((resolve,reject)=>{...})
    onFulfilled = typeof onFulfilled === "function"
      ? onFulfilled
      : (value) => value;
    onRejected = typeof onRejected === "function"
      ? onRejected
      : (reason) => { throw reason };


    // 返回新的 Promise 对象
    let promise2 = new MyPromise((resolve, reject) => {

      // executor内为同步代码、且状态为FULFILLED
      if (this.status == FULFILLED) {
        // 之所以使用 setTimeout,因为调用 then 的时候,resolvePromise中的 promise2 还没结果
        setTimeout(() => {
          // 处理结果中抛出异常的情况,如:throw new Error()
          try {
            // 利用p1的值、结合p2成功回调、计算 p2 成功回调的值
            let res = onFulfilled(this.value)
            // 返回 promise2 的值,继续执行 then.() 连续下去
            resolvePromise(promise2, res, resolve, reject)
          } catch (error) {
            reject(error);
          }
        }, 0);//具体延迟执行的时间>=4ms;
      }

      // executor内为同步代码、且状态为REJECTED
      if (this.status == REJECTED) {
        setTimeout(() => {
          try {
            let res = onRejected(this.reason)
            resolvePromise(promise2, res, resolve, reject)
          } catch (error) {
            reject(error);
          }
        }, 0);
      }

      // executor内为异步代码:收集所有的成功或失败的回调函数
      if (this.status == PENDING) {
        // 订阅:收集成功函数
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              let res = onFulfilled(this.value)
              resolvePromise(promise2, res, resolve, reject)
            } catch (error) {
              reject(error);
            }
          }, 0);
        })

        // 订阅:收集失败函数
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let res = onRejected(this.reason)
              resolvePromise(promise2, res, resolve, reject)
            } catch (error) {
              reject(error);
            }
          }, 0);
        })
      }
    })

    // 返回 promise2
    return promise2;
  }

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

  resolve(value) {
    return new MyPromise((resolve, reject) => {
      resolve(value);
    })
  }

  reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason);
    })
  }

  // 所有实例执行成功才算成功
  // 注意 1:try{ Promise.all() }catch{} 是捕获不到错误的,内容已经处理过了
  // 注意 2:Promise.all().catch() 可以捕获到错误
  all(promiseArray) {
    if (!Array.isArray(promiseArray)) {
      throw new Error("请传入PromiseArray")
    }

    return new MyPromise((resolve, reject) => {
      try {
        const resultArray = [];
        const length = promiseArray.length;
        for (let i = 0; i < length; i++) {
          promiseArray[i].then(data => {
            resultArray.push(data);
            if (resultArray.length === length) {
              resolve(resultArray)
            }
          }, reject)
        }
      } catch (e) {
        reject(e)
      }
    })
  }

  // 返回第一个改变状态的结果,无论成功的还是失败的
  race(promiseArray) {
    if (!Array.isArray(promiseArray)) {
      throw new Error("请传入PromiseArray")
    }
    return new MyPromise((resolve, reject) => {
      try {
        const length = promiseArray.length;
        for (let i = 0; i < length; i++) {
          promiseArray[i].then(resolve, reject);
        }
      }
      catch (e) {
        reject(e)
      }
    })
  }
}

// 处理then中成功函数或失败函数的返回值
// promise2 : then中新的promise对象
// res :上一个promise的返回值
// resolve : promise2中的第一个参数
// reject : promise2中的第二个参数
function resolvePromise(promise2, res, resolve, reject) {
  // 如果 promise2 等于 res,抛出异常
  // 例如:let promise1 = promise.then((value) => { return promise1; })
  if (promise2 == res) {
    return reject(new TypeError('Changing ...'))
  }

  // 若res为一个object 或 function
  if ((typeof res === "object" && res !== null) || (typeof res === "function")) {

    // 保证res.then取值的时候出现异常
    try {
      // 判断是否为 promise 对象
      let then = res.then;

      // 判断回调函数是否被多次调用过:成功就不能再失败、失败就不能再成功
      let called = false;

      // 如果 res 为promise对象,递归调用
      if (typeof then === "function") {
        // y:最内层的promise手动传入或计算的值
        // 一直由内层向外层反
        then.call(res, (y) => {
          // 避免重复调用
          if (called) return;
          called = true;

          // 如果Y为Promise对象,递归调用
          // 如果Y为普通值,相当于下次直接调用 - resolve()
          resolvePromise(promise2, y, resolve, reject)
        }, (r) => {
          // 避免重复调用
          if (called) return;
          called = true;
          reject(r)
        })
      } else {
        // res为普通值,直接调用resolve返回
        resolve(res);
      }
    } catch (error) {
      // 避免重复调用
      if (called) return;
      called = true;
      reject(error)
    }
  } else {
    // res为普通值,直接调用resolve返回
    resolve(res);
  }
}
const p1 = new MyPromise((resolve, reject) => {
  reject(1)
})

const p2 = p1.then((res) => {
  return res + 1;
}, err => {
  return err + 2
})

p2.then((res) => {
  console.log("res", res);
}, err => {
  console.log('err', err);
})