Promise 源码分析

1、引入Promise

  • 字面意义”承诺”,将来的某个时间进行兑现
  • 主要解决地域回调问题
  • Promise是异步的一种解决方案
  • Promise是一个构造函数,有属性和方法;通过new实例化使用

2、Promise相关特点

Promise – ( 兑现承诺 )

  • 要么成功要不失败,只能有一个结果

excutor – ( 执行器函数 )

  • 当 new Promise(excutor) 的时候,excutor函数自动执行;( 同步执行 )

  • excutor函数有两个参数:resolve – 成功的回调函数 和 reject – 失败的回调函数

then – ( 链式调用 )

  • then是异步调用的: 内部是利用微任务 或 宏任务处理

  • 每次调用then都返回一个新的Promise对象(继续下次链式调用)

  • then(call1,call2)方法里两个回调函数,即成功的回调和失败回调

  • then(call1,call2)本次执行call2方法,如果继续调用then方法

    • 本次call2执行结果为”成功”,下次then就执行call1
    • 本次call2执行结果为”失败”,下次then就执行call2
  • 穿透作用:如果上个then函数没,没有对应函数的处理,就会在下一个then的回调对应执行

    • let promise = new Promise((resolve, reject) => { resolve(“new Promise”) });
    • promise.then()
    • .then((value) => {
      • console.log(“—“, value); //new Promise
    • }, (reason) => {
      • console.log(“—“, reason);
    • })

catch – ( 链式调用 )

  • 内部的执行原理:then(null,callBacks)

  • 不影响继续调用 then 方法

  • 会受到前面then方法的第二个回调函数拦截

3、源码解析

步骤分析
  • 1、new MyPromise() 时自动触发executor函数(同步执行)
  • 2、调用then方法时,收集成功或失败函数(前提executor内异步执行)
  • 3、手动调用resolve或reject时,异步循环执行上一步收集的函数
  • 4、对上一步每次函数的执行结果放到resolvePromise函数中做处理
源码实现
const PENDING = "PENDING",
  FULFILLED = "FULFILLED",
  REJECTED = "REJECTED";


class MyPromise {
  //executor
  ///1、自执行函数,new MyPromise时立刻执行
  ///2、包含两个参数:resolve和reject函数
  constructor(executor) {

    this.status = PENDING;
    this.value = undefined;
    this.reason = undefined;

    // 分别盛放所有的成功或失败的回调函数
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    // 不放到原型上:resolve和reject
    // 由于每次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());
      }
    }

    // 实例化时:executor函数内异常捕获处理 - 例如:throw new Error()
    try {
      // executor:此方法同步执行
      executor(resolve, reject);
    } catch (error) {
      reject(error)
    }
  }

  // 每个then都返回一个新的promie对象,进行链式调用
  then(onFulfilled, onRejected) {

    // 解决穿透问题:如果onFulfilled或onRejected为空,默认给一个函数
    // 例如: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) => {

      // 以下代码使用setTimeout包裹:
      /// 1、使用setTimeout(宏任务)的处理方式,确保可以取到当前promise2的对象
      /// 2、源码中用的是微任务的处理方式
      /// 3、保障了多次then的链式调用,等待上次执行结束后才能执行下次( 事件循环机制 )

      // 下列代码res的值作为resolve和reject返回值
      /// 1、可能为普通值
      /// 2、可能为primise对象
      /// 3、使用resolvePromise方法进行处理

      // 同步代码执行executor时,且状态为FULFILLED
      if (this.status == FULFILLED) {
        setTimeout(() => {
          // 处理结果中抛出异常的情况,如:throw new Error()
          try {
            let res = onFulfilled(this.value)
            // 处理返回值的函数
            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);
        })
      }
    })

    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);
    })
  }

  //所有实例执行成功才算成功
  all(promiseArray) {
    if (!Array.isArray(promiseArray)) {
      throw new TypeError(" The arguments should be an array!")
    }
    return new MyPromise((resolve, reject) => {
      try {
        const resultArray = [];
        const length = promiseArray.length;

        // 有一个实例失败直会接执行reject方法;
        //否则等待所有实例执行完执行resolve方法
        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 TypeError(" The arguments should be an array!")
    }
    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中成功函数或失败函数的返回值
function resolvePromise(promise2, res, resolve, reject) {

  // 如果promise2等于res,抛出异常
  // 例如:let promise1 = promise.then((value) => { return promise1; })
  if (promise2 == res) {
    return reject(new TypeError('Changing cycle detected for promise #<MyPromise>'))
  }

  // 如果res是一个object或function时
  if ((typeof res === "object" && res !== null) || (typeof res === "function")) {
    //保证res.then取值的时候出现异常
    try {
      let then = res.then;//判断是否为 promise 对象

      //判断回调函数是否被多次调用过:例如 - resolve();resolve();连续多次调用
      let called = false;

      //为promise对象
      if (typeof then === "function") {
        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 {
        resolve(res);
      }
    } catch (error) {
      // 避免重复调用
      if (called) return;
      called = true;
      reject(error)
    }
  }
  //res为普通值
  else {
    resolve(res);
  }
}

module.exports = MyPromise;
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享