返回

不造个玩具 Promise 再走?

前端

各位技术控,大家好,好久没写文章了,今天带大家撸一个玩具 Promise。说实话类似的文章已经不少,不少大神都有实现版本,但是自己消化了才是最好的。在参考文章中,我还遇到了不少坑,比如 then 中的异步实现。

了解 Promise

Promise 是 JavaScript 中用于异步编程的神器,它让我们可以优雅地处理异步操作。Promise 有三个状态:pending(等待)、fulfilled(已完成)和 rejected(已拒绝)。

Promise 的用法很简单,它有两个参数,一个是 resolve,一个是 reject。resolve 表示操作成功,reject 表示操作失败。

当我们调用 Promise 时,它会立即执行,并返回一个 Promise 对象。这个 Promise 对象代表了异步操作的结果。

如果异步操作成功,则调用 resolve,Promise 对象的状态变为 fulfilled。如果异步操作失败,则调用 reject,Promise 对象的状态变为 rejected。

一旦 Promise 对象的状态改变,它就会通知它的 then 方法。then 方法有两个参数,一个是成功回调,一个是失败回调。

成功回调会在 Promise 对象的状态变为 fulfilled 时执行,失败回调会在 Promise 对象的状态变为 rejected 时执行。

实现玩具 Promise

现在,我们来实现一个玩具 Promise。

class Promise {
  constructor(executor) {
    this.state = 'pending';
    this.value = null;
    this.reason = null;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (err) {
      this.reject(err);
    }
  }

  resolve(value) {
    if (this.state !== 'pending') return;

    this.state = 'fulfilled';
    this.value = value;
    this.onFulfilledCallbacks.forEach(fn => fn(value));
  }

  reject(reason) {
    if (this.state !== 'pending') return;

    this.state = 'rejected';
    this.reason = reason;
    this.onRejectedCallbacks.forEach(fn => fn(reason));
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    const promise = new Promise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        }, 0);
      } else if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise, x, resolve, reject);
          } catch (err) {
            reject(err);
          }
        }, 0);
      } else {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolvePromise(promise, x, resolve, reject);
            } catch (err) {
              reject(err);
            }
          }, 0);
        });
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolvePromise(promise, x, resolve, reject);
            } catch (err) {
              reject(err);
            }
          }, 0);
        });
      }
    });

    return promise;
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }

  finally(onFinally) {
    return this.then(
      value => Promise.resolve(onFinally()).then(() => value),
      reason => Promise.resolve(onFinally()).then(() => { throw reason })
    );
  }
}

function resolvePromise(promise, x, resolve, reject) {
  if (promise === x) {
    reject(new TypeError('Chaining cycle detected'));
  }

  if (x instanceof Promise) {
    x.then(resolve, reject);
  } else if (x && (typeof x === 'object' || typeof x === 'function')) {
    let called = false;
    try {
      const then = x.then;
      if (typeof then === 'function') {
        then.call(
          x,
          y => {
            if (called) return;
            called = true;
            resolvePromise(promise, y, resolve, reject);
          },
          r => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        resolve(x);
      }
    } catch (err) {
      if (called) return;
      called = true;
      reject(err);
    }
  } else {
    resolve(x);
  }
}

结语

以上就是玩具 Promise 的实现,希望大家能够有所收获。Promise 是一个非常重要的概念,它可以帮助我们轻松地处理异步操作。如果你想深入了解 Promise,可以参考《深入理解 JavaScript》这本书。