深入分析Promise实现细节

118 阅读4分钟

说起手写Promise 在我入行没多久的时候,其实就看了相关了源码的解析视频,那时候跟着视频一点点的写,毕竟看着视频写跟抄没什么区别 ,看完之后也是一知半解的感觉,但是那时候也没有很想深入的去了解它。从那以后就搁置了很久没有再看了。

今天再提起这个是为了复习一下以前的知识巩固一下,方便以后自己复习,废话不多说直接开干

那我就从 new Promise 开始

首先我们知道我们平常使用过程中都是通过new Promise去使用的,然后抛出一个Promise对象包含then方法并返回成功内容。

const p1 = new Promise((resolve, reject) => {
    resolve(1)
  });
  
 p1.then((res) => {
   console.log(res) // 1
 })

那我们先来分析一下要实现这些要具备的条件

  1. promise有三种状态分别为:pending、fufilled、rejected,并且这三种状态是不可逆的
  2. 返回存在成功值和失败值
  3. 成功回调和错误回调

基于上面三点来实现一个初版Promise

 /**
 * 初始状态
 */
const PENDING = "PENDING";
/**
 * 成功状态
 */
const FULFILLED = "FULFILLED";
/**
 * 失败状态
 */
const REJECTED = "REJECTED";


  class MyPromise {
  constructor(executor) {
    /**
     * 状态
     */
    this.state = PENDING;

    /**
     * 存放成功值
     */
    this.value;

    /**
     * 存放失败值
     */
    this.reason;

    /**
     * 成功回调
     */
    let resolve = (value) => {
      if (this.state === PENDING) {
        this.value = value;
        this.state = FULFILLED;
      }
    };

    /**
     * 失败回调
     */
    let reject = (reason) => {
      if (this.state === PENDING) {
        this.reason = reason;
        this.state = REJECTED;
      }
    };

    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
  then(onFulfilled, onRejected) {
     if(this.state === FULFILLED) {
      onFulfilled(this.value)
     }
     
     if(this.state === REJECTED) {
      onRejected(thi.value)
     }

  }
}

现在去使用一下MyPromise看是否生效

  const p2 = new MyPromise((resolve,reject) => {
    resolve(2)
  });
  
  p2.then(res => {
    console.log(res); // 2
  })

我们看到控制台打印出了成功结果2 说明目前已经成功了一部分

但是如果我们这里使用了setTimeout的话就有问题,没有打印结果


const p2 = new MyPromise((resolve,reject) => {
   setTimeout(() => {
      resolve(2)
   },0)
  });
  
  p2.then(res => {
  })

这是什么原因呢因为我们刚才没有考虑异步的情况,当我们调用then的时候state还是pending状态,没有执行回调,那该如何处理呢,我们需要对异步情况进行处理

/**
 * 初始状态
 */
const PENDING = "PENDING";
/**
 * 成功状态
 */
const FULFILLED = "FULFILLED";
/**
 * 失败状态
 */
const REJECTED = "REJECTED";


  class MyPromise {
  constructor(executor) {
    /**
     * 状态
     */
    this.state = PENDING;

    /**
     * 存放成功值
     */
    this.value;

    /**
     * 存放失败值
     */
    this.reason;
    
    /**
     * 存放成功回调集合
     */
    this.onFulfilledCallback = [];

    /**
     * 存放失败回调集合
     */
    this.onRejectedCallback = [];

    /**
     * 成功回调
     */
    let resolve = (value) => {
      if (this.state === PENDING) {
        this.value = value;
        this.state = FULFILLED;
        this.onFulfilledCallback.forEach((fn) => fn());
      }
    };

    /**
     * 失败回调
     */
    let reject = (reason) => {
      if (this.state === PENDING) {
        this.reason = reason;
        this.state = REJECTED;
        this.onRejectedCallback.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
  then(onFulfilled, onRejected) {
     if(this.state === FULFILLED) {
      onFulfilled(this.value)
     }
     
     if(this.state === REJECTED) {
      onRejected(thi.reason)
     }
     
     if(thi.state === PENDING) {
       this.onFulfilledCallback.push(() => {
         onFulfilled(this.value)
       })
       this.onRejectedCallback.push(() => {
         onRejected(this.reason)
       })
     }

  }
}

通过判断state状态给成功和失败回到添加到回调里面,当调用resolve 或者 reject的时候 我们就可以对集合里面的事件进行统一处理, 从而处理异步的情况,到这里一个简版的Promise就实现完成了

完善Promise 实现链式调用

function resolvePromise(promise2, x, resolve, reject) {
  let called; // 避免重复调用成功失败
  // 判断循环引用
  if (promise2 === x) {
    return new TypeError("循环引用了");
  }

  // 判断数据类型
  if ((typeof x === "object" && x !== null) || typeof c === "function") {
    try {
      let then = x.then; // 这里有可能then是用 defineProperity来定义的
      if (typeof then === "function") {
        // 暂且当做是 promise
        then.call(
          x,
          (y) => {
            if (called) {
              return;
            }
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          (n) => {
            if (called) {
              return;
            }
            called = true;
            reject(n);
          }
        );
      } else {
        // 普通对象直接返回成功
        resolve(x);
      }
    } catch (e) {
      if (called) {
        return;
      }
      called = true;
      reject(e);
    }
  }
}
class MyPromise {
  constructor(executor) {
    /**
     * 状态
     */
    this.state = PENDING;

    /**
     * 存放成功值
     */
    this.value;

    /**
     * 存放失败值
     */
    this.reason;

    /**
     * 存放成功回调集合
     */
    this.onFulfilledCallback = [];

    /**
     * 存放失败回调集合
     */
    this.onRejectedCallback = [];

    /**
     * 成功回调
     */
    let resolve = (value) => {
      if (this.state === PENDING) {
        this.value = value;
        this.state = FULFILLED;
        this.onFulfilledCallback.forEach((fn) => fn());
      }
    };

    /**
     * 失败回调
     */
    let reject = (reason) => {
      if (this.state === PENDING) {
        this.reason = reason;
        this.state = REJECTED;
        this.onRejectedCallback.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
  then(onFulfilled, onRejected) {
    // onFulfilled onRejected 可能都为空v 可能为空 但是还是要继续传递下去 例如 then().then().then(data => data)
    onFulfilled =
      typeof onFulfilled === "function" ? onFulfilled : (data) => data;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (err) => {
            throw err;
          };

    // 为了链式调用这里返回一个promise
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        setTimeout(() => {
          try {
            // 对then方法里面的 返回值做处理
            let x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        }, 0);
      }

      if (this.state === REJECTED) {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        }, 0);
      }

      if (this.state === PENDING) {
        this.onFulfilledCallback.push(() => {
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (err) {
              reject(err);
            }
          }, 0);
        });

        this.onRejectedCallback.push(() => {
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (err) {
              reject(err);
            }
          }, 0);
        });
      }
    });

    return promise2;
  }
}

实现Promise.all方法

/**
 * 返回全部成功的结果
 */
MyPromise.all = function (values) {
  return new MyPromise((resolve, reject) => {
    let arr = [];
    /**
     * 这里为何要使用index 而不是使用 arr.length呢
     * 因为then 是异步的 当for循环结束了arr长度也就是valus长度
     * 但是这个试试异步任务还未结束 resolve里面的值是空的
     */
    let index = 0;
    function processData(key, value) {
      arr[key] = value;
      ++index;
      if (index === values.length) {
        resolve(arr);
      }
    }
    for (let i = 0; i < values.length; i++) {
      const current = values[i];
      if (isPromise(current)) {
        current.then((data) => {
          processData(i, data);
        }, reject);
      } else {
        processData(i, current);
      }
    }
  });
};

实现Promise.resc方法

/**
 * race 谁先成功或失败就返回谁
 */
MyPromise.race = function (values) {
  return new MyPromise((resolve, reject) => {
    for (let i = 0; i < values.length; i++) {
      let current = values[i];
      if (isPromise(current)) {
        current.then(
          (data) => {
            resolve(data);
          },
          (err) => {
            reject(err);
          }
        );
      } else {
        resolve(current);
      }
    }
  });
};

实现Promise.resolve方法

/**
 * Promise.resolve
 */
MyPromise.resolve = function (value) {
  return new MyPromise((resolve, reject) => {
    if (isPromise(value)) {
      value.then(resolve, reject);
    } else {
      resolve(value);
    }
  });
};

实现Promise.reject 方法


/**
 * Promise.reject
 */
MyPromise.reject = function (reason) {
  return new MyPromise((resolve, reject) => {
    reject(reason);
  });
};

手写Promise github源码地址