Promise底层源码解析

354 阅读4分钟

Promise底层源码解析

Promise 是 JavaScript 中一种非常重要的异步编程解决方案,也是 ES6 引入的新特性之一。它可以帮助我们优雅地处理异步操作,并解决了回调函数地狱的问题。在本篇文章中,我们将深入剖析 Promise 的底层源码,了解其实现原理。

Promise 简介

Promise 可以看作是一种对象,它可以帮助我们处理异步操作。一个 Promise 对象有三种状态:

  • pending:表示等待状态,即操作尚未完成。
  • fulfilled:表示操作成功完成。
  • rejected:表示操作失败。

当 Promise 状态变为 fulfilledrejected 时,我们通常称为 Promise 已经“settled”。

Promise 的基本用法

在 JavaScript 中,我们可以通过以下方式来创建一个 Promise 对象:

const promise = new Promise((resolve, reject) => {
  // 异步操作
  if (/* 操作成功 */) {
    resolve(value); // 将 Promise 状态设置为 fulfilled
  } else {
    reject(error); // 将 Promise 状态设置为 rejected
  }
})

在上述代码中,我们使用 new Promise() 方法创建了一个 Promise 对象,并传入了一个函数,该函数包含了异步操作。当异步操作执行成功后,我们可以调用 resolve() 方法将 Promise 状态设置为 fulfilled,并返回对应的数据;反之,我们可以调用 reject() 方法将 Promise 状态设置为 rejected,并返回对应的错误信息。

在 Promise 对象创建完成后,我们可以使用 then()catch() 方法来处理 Promise 对象的状态变化:

promise.then((value) => {
  // 操作成功,处理返回的 value 数据
}).catch((error) => {
  // 操作失败,处理返回的 error 错误信息
})

在上述代码中,当 Promise 状态变为 fulfilled 时,我们会调用 then() 方法,并传入一个回调函数,该函数会被执行并接收传入的 value 值作为参数;反之,当 Promise 状态变为 rejected 时,我们会调用 catch() 方法,并传入一个回调函数,该函数会被执行并接收传入的 error 错误信息作为参数。

Promise 底层源码解析

Promise 的底层源码包含了两个重要的类:PromisePromiseState。其中,PromiseState 包含了 Promise 对象的三种状态:PENDINGFULFILLEDREJECTEDPromise 则是 Promise 对象的核心实现类,包含了 Promise 状态及操作的核心逻辑。

下面是 Promise 的底层源码实现,供读者参考:

class PromiseState {
  static PENDING = 'pending';
  static FULFILLED = 'fulfilled';
  static REJECTED = 'rejected';

  constructor(state) {
    this.state = state || PromiseState.PENDING;
    this.value = null;
    this.reason = null;
    this.fulfillCallbacks = [];
    this.rejectCallbacks = [];
  }

  fulfill(value) {
    if (this.state === PromiseState.PENDING) {
      this.state = PromiseState.FULFILLED;
      this.value = value;

      for (let i = 0; i < this.fulfillCallbacks.length; i++) {
        this.fulfillCallbacks[i](value);
      }
    }
  }

  reject(reason) {
    if (this.state === PromiseState.PENDING) {
      this.state = PromiseState.REJECTED;
      this.reason = reason;

      for (let i = 0; i < this.rejectCallbacks.length; i++) {
        this.rejectCallbacks[i](reason);
      }
    }
  }

  then(onFulfilled, onRejected) {
    const nextPromiseState = new PromiseState();

    if (this.state === PromiseState.PENDING) {
      this.fulfillCallbacks.push((value) => {
        try {
          const x = onFulfilled(value);
          resolvePromise(nextPromiseState, x);
        } catch (e) {
          nextPromiseState.reject(e);
        }
      });

      this.rejectCallbacks.push((reason) => {
        try {
          const x = onRejected(reason);
          resolvePromise(nextPromiseState, x);
        } catch (e) {
          nextPromiseState.reject(e);
        }
      });
    } else if (this.state === PromiseState.FULFILLED) {
      setTimeout(() => {
        try {
          const x = onFulfilled(this.value);
          resolvePromise(nextPromiseState, x);
        } catch (e) {
          nextPromiseState.reject(e);
        }
      }, 0);
    } else if (this.state === PromiseState.REJECTED) {
      setTimeout(() => {
        try {
          const x = onRejected(this.reason);
          resolvePromise(nextPromiseState, x);
        } catch (e) {
          nextPromiseState.reject(e);
        }
      }, 0);
    }

    return nextPromiseState;
  }

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

function resolvePromise(promiseState, x) {
  if (x === promiseState) {
    throw new TypeError('Chaining cycle detected for promise');
  }

  if (x && typeof x === 'object' || typeof x === 'function') {
    let used = false;

    try {
      const then = x.then;

      if (typeof then === 'function') {
        then.call(x, (y) => {
          if (used) {
            return;
          }

          used = true;
          resolvePromise(promiseState, y);
        }, (r) => {
          if (used) {
            return;
          }

          used = true;
          promiseState.reject(r);
        });
      } else {
        promiseState.fulfill(x);
      }
    } catch (e) {
      if (used) {
        return;
      }

      used = true;
      promiseState.reject(e);
    }
  } else {
    promiseState.fulfill(x);
  }
}

class Promise {
  constructor(fn) {
    if (typeof fn !== 'function') {
      throw new TypeError('Promise resolver ' + fn + ' is not a function');
    }

    const state = this.state = new PromiseState();

    try {
      fn((value) => {
        resolvePromise(state, value);
      }, (reason) => {
        state.reject(reason);
      })
    } catch (e) {
      state.reject(e);
    }
  }

  then(onFulfilled, onRejected) {
    return this.state.then(onFulfilled, onRejected);
  }

  catch(onRejected) {
    return this.state.catch(onRejected);
  }
}

Promise.resolve = function (value) {
  return new Promise((resolve) => {
    resolve(value);
  });
}

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

在上述代码中,我们首先定义了 PromiseState 类,该类包含了 Promise 对象的三种状态及其对应的操作方法。其中,fulfill() 方法用于将 Promise 状态设置为 fulfilledreject() 方法用于将 Promise 状态设置为 rejectedthen()catch() 方法用于处理 Promise 状态的变化。

我们还定义了 resolvePromise() 方法,该方法用于处理 Promise 对象的值。当该值为 Promise 对象时,我们会递归调用 then() 方法,直到获取到一个非 Promise 类型的值为止。当该值为其他类型时,我们直接使用 fulfill() 方法将 Promise 状态设置为 fulfilled

最后,我们定义了 Promise 类,该类实现了 Promise 对象的核心逻辑,并暴露了 then()catch()static 方法。对外部使用者而言,只需要使用 new Promise() 创建一个 Promise 对象,并调用 then()catch() 方法即可。

结语

以上是 Promise 的底层源码解析,通过深入理解 Promise 的底层实现原理,可以更好地掌握 Promise 的使用方法和技巧。希望这篇文章对您有所帮助!