Skip to content

手写 promise-then 的回调执行时机

目标

实现示例的 then 方法

js
const p = new MyPromise((res, rej) => {
  // ...
});

p.then(
  (res) => {},
  (err) => {}
);

代码

初始代码

js
  then(onFulfilled, onRejected) {
    // .then 返回的也是一个 promise
    return new MyPromise((resolve, reject) => {
      if (this.#state === FULFILLED) {
        onFulfilled(this.#result)
      } else if (this.#state === REJECTED) {
        onRejected(this.#result)
      } else {
        // 还是pending 状态, 这里是异步的情况
        // 由于 then 方法已经执行过了, 等到promise状态变更后, 无法再次执行
        // 需要放到changeState中才能处理
        // eg: p.then((res) => { setTimeout(()=> res('success'), 10000)})
      }
    })
  }

将 then 中的参数暂存, 在状态更改后调用, 如图

改进完整代码, 高亮位置为新增代码

js
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  /**
   * 创建一个 promise
   * @param {Function} executor 任务执行器, 立即执行 类比 new promise((res, rej)=>{}) 中的 (res, rej)=>{}
   */
  constructor(executor) {
    // 注意只能捕获同步错误
    try {
      executor(this.#resolve, this.#reject);
    } catch (error) {
      // 执行期间报错
      this.#reject(error);
    }
  }

  #state = PENDING; // 状态
  #result = undefined; // 数据
  #handlers = []; // 实例.then 中注册的所有处理方法

  /**
   * 标记当前任务完成 注意 this 绑定, 这里使用箭头函数, 下同
   * @param {any} data 任务完成的相关数据
   */
  #resolve = (data) => {
    this.#changeState(FULFILLED, data);
  };
  /**
   * 标记当前任务失败
   * @param {any} reason 任务失败的相关数据
   */
  #reject = (reason) => {
    this.#changeState(REJECTED, reason);
  };

  // 改变状态和数据
  #changeState(state, result) {
    // 状态如果已经更改, 不再执行
    if (this.#state !== PENDING) return;
    this.#state = state;
    this.#result = result;
    console.log('promise状态:', this.#state);
    console.log('promise结果:', this.#result);
    this.#run();
  }

  // then 中的函数处理
  #run() {
    if (this.#state === PENDING) return;
    while (this.#handlers.length) {
      const { onFulfilled, onRejected, resolve, reject } = this.#handlers.shift();
      if (this.#state === FULFILLED) {
        if (typeof onFulfilled === 'function') {
          onFulfilled(this.#result);
        }
      } else if (this.#state === REJECTED) {
        if (typeof onFulfilled === 'function') {
          onRejected(this.#result);
        }
      }
    }
  }

  then(onFulfilled, onRejected) {
    // .then 返回的也是一个 promise
    return new MyPromise((resolve, reject) => {
      // 暂存状态
      this.#handlers.push({
        onFulfilled,
        onRejected,
        resolve,
        reject
      });
      this.#run();
    });
  }
}

测试用例

单个 then 函数

js
const p = new MyPromise((res, rej) => {
  setTimeout(() => {
    res('11111111');
  }, 1000);
});

p.then(
  (res) => {
    console.log('@@@promise 完成1:', res);
  },
  (err) => {
    console.log('@@@promise 失败1:', err);
  }
);

// promise状态: fulfilled
// promise结果: 11111111
// @@@promise 完成1: 11111111

多个 then 函数

js
const p = new MyPromise((res, rej) => {
  setTimeout(() => {
    res('11111111');
  }, 1000);
});

p.then(
  (res) => {
    console.log('@@@promise 完成1:', res);
  },
  (err) => {
    console.log('@@@promise 失败1:', err);
  }
);
p.then(
  (res) => {
    console.log('@@@promise 完成2:', res);
  },
  (err) => {
    console.log('@@@promise 失败2:', err);
  }
);
p.then(
  (res) => {
    console.log('@@@promise 完成3:', res);
  },
  (err) => {
    console.log('@@@promise 失败3:', err);
  }
);
// promise状态: fulfilled
// promise结果: 11111111
// @@@promise 完成1: 11111111
// @@@promise 完成2: 11111111
// @@@promise 完成3: 11111111

then 的回调不是函数

js
const p = new MyPromise((res, rej) => {
  setTimeout(() => {
    res('11111111');
  }, 1000);
});
// then 的第一个参数不是函数
p.then(null, (err) => {
  console.log('@@@promise 失败3:', err);
});
p.then(
  (res) => {
    console.log('@@@promise 完成4:', res);
  },
  (err) => {
    console.log('@@@promise 失败4:', err);
  }
);

// promise状态: fulfilled
// promise结果: 11111111
// @@@promise 完成4: 11111111