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

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


一、Promise 的状态

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

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

⚠️ 特点:

  • 状态 只能从 pending → fulfilledpending → 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 → fulfilledpending → rejected,不可逆。

  • 方法

    • 实例方法:thencatchfinally
    • 静态方法:resolverejectallallSettledraceany
  • 原理

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

相关推荐
Mintopia3 小时前
🌐 Web3.0 时代:AIGC 如何赋能去中心化内容生态?
前端·javascript·aigc
光影少年3 小时前
next.js和nuxt与普通csr区别
nuxt.js·掘金·金石计划·next.js
然我3 小时前
面试官:这道 Promise 输出题你都错?别再踩 pending 和状态凝固的坑了!(附超全解析)
前端·javascript·面试
bug_kada4 小时前
让你彻底明白什么是闭包(附常见坑点)
前端·javascript
光影少年4 小时前
js异步解决方案以及实现原理
前端·javascript·掘金·金石计划
阿隆_趣编程4 小时前
为了方便相亲,我用AI写了一款小程序
前端·javascript·微信小程序
EndingCoder4 小时前
Electron 跨平台兼容性:处理 OS 差异
前端·javascript·electron·前端框架·node.js·chrome devtools
zhong liu bin4 小时前
Vue框架技术详解——项目驱动概念理解【前端】【Vue】
前端·javascript·vue.js·vscode·vue
前端 贾公子4 小时前
ElementUI 中 validateField 对部分表单字段数组进行校验时多次回调问题
前端·javascript·elementui