Promise状态和方法都有哪些,以及实现原理

很好 👌 你问的是 Promise 的状态、方法,以及实现原理。我帮你拆成三部分来讲:


一、Promise 的状态

Promise 内部有 三种状态 ([[PromiseState]]):

  1. pending(进行中):初始状态,既没有被 fulfilled,也没有被 rejected。
  2. fulfilled (已成功):操作成功完成,并返回一个值(用 resolve 触发)。
  3. rejected (已失败):操作失败,并返回失败原因(用 reject 触发)。

⚠️ 特点:

  • 状态 只能从 pending → fulfilled 或 pending → rejected ,一旦变化就 不可逆。
  • 成功和失败只能发生一次,后续调用 resolve / reject 不会再改变状态。

二、Promise 的方法

1. 实例方法

  • then(onFulfilled, onRejected)

    • 注册成功和失败的回调。
    • 返回一个新的 Promise(可链式调用)。
    • 如果 onFulfilled / onRejected 返回值是 Promise,会进行 状态递归解析。
  • catch(onRejected)

    • 相当于 .then(undefined, onRejected)。
    • 用于错误捕获。
  • finally(onFinally)

    • 无论成功/失败都会执行。
    • 不会改变链式调用的结果,只做副作用处理。

2. 静态方法

  • Promise.resolve(value)

    • 返回一个 fulfilled 状态的 Promise。
    • 如果参数本身是 Promise,直接返回。
  • Promise.reject(reason)

    • 返回一个 rejected 状态的 Promise。
  • Promise.all(iterable)

    • 并行执行多个 Promise,所有都成功才成功,否则第一个失败就失败。
  • Promise.allSettled(iterable)

    • 等待所有 Promise 执行完,不管成功/失败,返回每个结果的数组。
  • Promise.race(iterable)

    • 谁先有结果(成功或失败)就返回谁的结果。
  • Promise.any(iterable)

    • 只要有一个成功就返回成功,如果全部失败则返回 AggregateError。

三、Promise 实现原理

Promise 的核心是 发布-订阅模式 + 状态机 + 事件循环。

1. 基础结构

一个 Promise 对象要有:

  • state:存储当前状态(pending / fulfilled / rejected)。
  • value / reason:存储成功的值或失败的原因。
  • handlers:存放 then 注册的回调函数。

2. 构造函数

ini 复制代码
class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };

    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };

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

3. then 方法

  • 返回一个新的 Promise(支持链式调用)。
  • 根据状态执行不同的回调。
  • 若回调返回的是 Promise,需要递归解析(即 Promise 解决过程)。
ini 复制代码
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
    onRejected = typeof onRejected === 'function' ? onRejected : e => { throw e };

    const promise2 = new MyPromise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        queueMicrotask(() => { // 保证异步
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }

      if (this.state === 'rejected') {
        queueMicrotask(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }

      if (this.state === 'pending') {
        this.onFulfilledCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              const x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });

        this.onRejectedCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              const x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });
      }
    });

    return promise2;
  }
}

4. resolvePromise 函数(核心)

处理 then 回调返回值的逻辑:

  • 如果返回的是 普通值 ,直接 resolve。
  • 如果返回的是 Promise,递归解析其状态。
  • 避免 循环引用。
ini 复制代码
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected'));
  }

  if (x && (typeof x === 'object' || typeof x === 'function')) {
    let called = false;
    try {
      let then = x.then;
      if (typeof then === 'function') {
        then.call(x, y => {
          if (called) return;
          called = true;
          resolvePromise(promise2, y, resolve, reject);
        }, e => {
          if (called) return;
          called = true;
          reject(e);
        });
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}

四、总结

  • 状态 :pending → fulfilled 或 pending → rejected,不可逆。

  • 方法:

    • 实例方法:then、catch、finally。
    • 静态方法:resolve、reject、all、allSettled、race、any。
  • 原理:

    • 通过状态机保证不可逆。
    • 使用回调队列保存 then 回调。
    • 返回新的 Promise 实现链式调用。
    • resolvePromise 负责递归解析,确保符合 Promise/A+ 规范。

相关推荐
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄3 天前
JavaScript 隐式全局变量解析
javascript
沙蒿同学3 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端
paopaokaka_luck3 天前
智慧社区综合服务小程序(人脸识别、AI问答、Echarts图形化分析)
前端·javascript·spring boot·spring·数据分析·echarts
Hilaku3 天前
为什么死磕 1px 的团队,用户体验反而更差?
前端·javascript·程序员
陈拉斯3 天前
给公司年会写了个大屏抽奖系统:动画在前端跑,凭什么说结果没被改?
javascript
yzy853 天前
Vue中下载或打开文件的JavaScript方法
前端·javascript·vue
用户298698530143 天前
在 React 中用 JavaScript 将 Word 转换为文本
前端·javascript·react.js
李少兄3 天前
深入解析 JavaScript 中的 `document` 对象
javascript