Skip to content

手写 Promise

实现 promise 常用方法

  • 初始化 & 异步调用
  • then catch 链式调用
  • 实现 API: .resolve .reject .all .race

代码实现 MyPromise

js
class MyPromise {
  state = 'pending'; //状态 pending,fulfilled,rejected
  value = undefined; // 成功后的值
  reason = undefined; // 失败后的原因

  resolveCallbacks = []; // pending 下,存储成功的回调
  rejectCallbacks = []; // pending 下,存储失败的回调

  constructor(fn) {
    const resolveHandler = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        // 状态变化后,函数执行
        this.resolveCallbacks.forEach((fn) => fn(this.value));
      }
    };

    const rejectHandler = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        // 状态变化后,函数执行
        this.rejectCallbacks.forEach((fn) => fn(this.reason));
      }
    };

    try {
      fn(resolveHandler, rejectHandler);
    } catch (err) {
      resolveHandler(err);
    }
  }

  then(fn1, fn2) {
    // 当 pending 下,fn1,fn2 存储到 callbacks 中
    fn1 = typeof fn1 === 'function' ? fn1 : (v) => v;
    fn2 = typeof fn2 === 'function' ? fn2 : (e) => e;

    // 函数还没执行,返回新的 promise
    if (this.state === 'pending') {
      const p1 = new MyPromise((resolve, reject) => {
        this.resolveCallbacks.push(() => {
          try {
            const newValue = fn1(this.value);
            resolve(newValue);
          } catch (err) {
            reject(err);
          }
        });
        this.rejectCallbacks.push(() => {
          try {
            const newReason = fn1(this.reason);
            reject(newReason);
          } catch (err) {
            reject(err);
          }
        });
      });
      return p1;
    }

    // fn1 函数执行,返回新的 promise
    if (this.state === 'fulfilled') {
      const p1 = new MyPromise((resolve, reject) => {
        try {
          const newValue = fn1(this.value);
          resolve(newValue);
        } catch (err) {
          reject(err);
        }
      });
      return p1;
    }

    // fn2 函数执行,返回新的 promise
    if (this.state === 'rejected') {
      const p1 = new MyPromise((resolve, reject) => {
        try {
          const newReason = fn2(this.reason);
          reject(newReason);
        } catch (err) {
          reject(err);
        }
      });
      return p1;
    }
  }

  // catch 就是 then 的一个语法糖,简单模式
  catch(fn) {
    return this.then(null, fn);
  }
}

// 全局静态方法
MyPromise.resolve = function (value) {
  return new MyPromise((resolve, reject) => resolve(value));
};

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

MyPromise.all = function (promiseList = []) {
  const p1 = new MyPromise((resolve, reject) => {
    const result = []; // 存储 promiseList 所有的结果
    const length = promiseList.length;
    let resolvedCount = 0;

    promiseList.forEach((p) => {
      p.then((data) => {
        result.push(data);

        // resolvedCount 必须在 then 里面做 ++
        // 不能使用 foreach 的 index,因为 index 是同步的
        resolvedCount++;
        if (resolvedCount == length) {
          // 已经到最后一个
          resolve(result);
        }
      }).catch((err) => {
        reject(err);
      });
    });
  });
  return p1;
};

MyPromise.race = function (promiseList = []) {
  let resolved = false; // 标记
  const p1 = new MyPromise((resolve, reject) => {
    promiseList.forEach((p) => {
      p.then((data) => {
        if (!resolved) {
          resolve(data);
          resolved = true;
        }
      }).catch((err) => {
        reject(err);
      });
    });
  });
  return p1;
};

测试代码

js
// 普通调用
const p1 = new MyPromise((resolve, reject) => {
  // resolve(100)
  // reject('错误...')
  setTimeout(() => {
    resolve(100);
  }, 1000);
});

// 链式调用
const p11 = p1.then((data1) => {
  console.log('data1', data1); // data1 100
  return data1 + 1;
});
const p12 = p11.then((data2) => {
  console.log('data2', data2); // data2 101
  return data2 + 1;
});
const p13 = p12.catch((err) => console.error(err));

// api 调用
const p2 = MyPromise.resolve(200);
const p3 = MyPromise.resolve(300);
const p4 = MyPromise.reject('错误...');
// 传入 promise 数组,等待所有的都 fulfilled 后,返回新的 promise 包含前面所有的结果
const p5 = MyPromise.all([p1, p2, p3]);
p5.then((result) => console.log('all result', result)); // all result (3)[200, 300, 100]
// 传入 promise 数组,只要有一个 fulfilled 即可返回
const p6 = MyPromise.race([p1, p2, p3]);
p6.then((result) => console.log('race result', result)); // race result 200

基于 MIT 许可发布