【JavaScript】实现类似promise的异步链式调用

2023/01/28 11:01:28

实现代码

class MyPromise {
  constructor(fn) {
    this.cbs = [];

    const resolve = (value) => {
      setTimeout(() => {
        this.data = value;
        this.cbs.forEach((cb) => cb());
      });
    };

    fn(resolve);
  }

  then(onResolved) {
    return new MyPromise((resolve) => {
      const cb = () => {
        const res = onResolved(this.data);
        if (res instanceof MyPromise) {
          res.then(resolve);
        } else {
          resolve(res);
        }
      };
      this.cbs.push(cb);
    });
  }
}

实现思路

promise 的理念就是设置回调函数(then())并由使用者决定何时触发回调函数以及给回调函数传什么值(resolve())。

根据一个示例来理解内部实现:

new MyPromise((resolve) => {
  setTimeout(() => {
    resolve(1);
  }, 500);
})
  .then((res) => {
    console.log(res);
    return new MyPromise((resolve) => {
      setTimeout(() => {
        resolve(2);
      }, 500);
    });
  })
  .then(console.log);

构造函数的实现

class MyPromise {
  constructor(fn) {
    this.cbs = [];

    const resolve = (value) => {
      setTimeout(() => {
        this.data = value;
        this.cbs.forEach((cb) => cb());
      });
    };

    fn(resolve);
  }
  // ...
}

这里重点在 resolve() 方法上,resolve() 方法接收一个值作为参数,这个值会被传递给 then(fn) 方法中的 fn 函数中。

resolve() 方法的最后开始执行 cbs 中的回调函数。

then(fn) 方法的实现

class MyPromise {
  // ...
  then(onResolved) {
    // return 的值为 promiseNew
    return new MyPromise((resolve) => {
      const cb = () => {
        const res = onResolved(this.data);
        if (res instanceof MyPromise) {
          // 此时 res 为 promiseCallback,将 promiseNew 的 resolve 方法注册为 promiseCallback 的回调
          // 这样等到 promiseCallback 上的回调执行完毕后才会执行 promiseNew 上的回调,以实现异步链式调用
          res.then(resolve);
        } else {
          resolve(res);
        }
      };
      // this 为 promiseOld
      this.cbs.push(cb);
    });
  }
}

then(fn) 方法中可能出现三个 MyPromise 实例,分别是:

  • 调用 then(fn) 方法的 MyPromise 实例,也就是当前的 MyPromise 实例,记作 promiseOld
  • then(fn) 方法将接收到的函数进行封装,返回一个新的 MyPromise 实例,记作 promiseNew
  • then(fn) 方法接收的回调函数的返回值,也就是 fn() 的返回值有可能是一个 MyPromise 实例,记作 promiseCallback

then(fn) 方法返回一个新的 MyPromise 实例 promiseNew,如果 fn() 的返回值也是 MyPromise 实例,那么 promiseNew 会等到 promiseCallback 的异步回调链执行完毕后再执行自己的 resolve() 方法。

参考

最简实现 Promise,支持异步链式调用(20 行)open in new window