Skip to content

Promise静态方法汇总

早期大家学习 Promise 的时候,都是从最基础的例子开始的,例如:

// 创建一个 Promise 实例
const myPromise = new Promise((resolve, reject) => {
// 模拟异步任务,例如 2 秒后返回数据
setTimeout(() => {
const success = true // 这里模拟任务是否成功
if (success) {
resolve('任务成功完成')
} else {
reject('任务失败')
}
}, 2000)
})
console.log('Promise 已创建,但任务还没完成...')
// 通过 .then() 处理成功结果,.catch() 处理失败结果
myPromise
.then((result) => {
console.log('成功回调:', result)
})
.catch((error) => {
console.error('失败回调:', error)
})
.finally(() => {
console.log('无论成功或失败,这里都会执行')
})

不过我们知道,Promise 实际上是一个类,目前 Promise 上面已经有越来越多的静态方法了。这篇文章,咱们就来将 Promise 上面众多的静态方法进行一个汇总。

首先,我们可以对 Promise 上面的静态方法分类,这里我将其分为两类:

  1. 组合类
  2. 工具类

组合类#

这类方法的主要作用是把多个 Promise 实例“组合”成一个新的 Promise,并根据一组 Promise 的整体状态来决定返回结果。

特点:

代表方法:

它们的关键词是:“一组任务 → 一个结果”

Promise.all#

Promise.all() 是 Promise 组合类方法中最常用的一个。它可以同时执行多个 Promise,并在所有 Promise 都成功时返回一个新的 Promise。只要有一个 Promise 失败,整个 Promise.all() 就会立刻变成失败状态。

你可以把它理解成“大家一起好,才算好”的模式。

语法

Promise.all(iterable)

示例代码

// 模拟一个延迟函数
function delay(ms, value, shouldReject = false) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldReject) {
reject(`任务 ${value} 失败`)
} else {
resolve(`任务 ${value} 完成`)
}
}, ms)
})
}
const task1 = delay(1000, 'A')
const task2 = delay(2000, 'B')
const task3 = delay(1500, 'C')
Promise.all([task1, task2, task3])
.then((results) => {
console.log('所有任务完成:', results)
})
.catch((error) => {
console.error('有任务失败:', error)
})

运行效果(全部成功时):

所有任务完成: [ '任务 A 完成', '任务 B 完成', '任务 C 完成' ]

运行效果(有一个失败时):

const task1 = delay(1000, 'A')
const task2 = delay(2000, 'B', true) // 第二个任务失败
const task3 = delay(1500, 'C')

输出:

有任务失败: 任务 B 失败

适用场景

Promise.allSettled#

Promise.allSettled()并行执行多个 Promise,并在*所有 Promise 都执行完毕(无论成功还是失败)时,返回一个新的 Promise。 它不会因为某个 Promise 失败而提前结束,而是等全部结果都返回,再一次性给你一个“结果快照”。

你可以把它理解成“不管成败,大家一起交作业”的模式。

语法

Promise.allSettled(iterable)

示例代码

// 模拟一个延迟函数
function delay(ms, value, shouldReject = false) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldReject) {
reject(`任务 ${value} 失败`)
} else {
resolve(`任务 ${value} 完成`)
}
}, ms)
})
}
const task1 = delay(1000, 'A')
const task2 = delay(2000, 'B', true) // 故意让第二个任务失败
const task3 = delay(1500, 'C')
Promise.allSettled([task1, task2, task3]).then((results) => {
console.log('所有任务的最终状态:', results)
})

运行效果:

所有任务的最终状态: [
{ status: 'fulfilled', value: '任务 A 完成' },
{ status: 'rejected', reason: '任务 B 失败' },
{ status: 'fulfilled', value: '任务 C 完成' }
]

适用场景

Promise.race#

Promise.race()并行执行多个 Promise,并在**第一个完成(无论成功还是失败)**的 Promise 状态确定后,立刻返回一个新的 Promise。

也就是说,谁先结束,就用谁的结果(或错误)作为最终返回值,其它 Promise 的结果会被忽略。

你可以把它理解成“赛跑”模式——只看谁先到终点,至于其他人后来跑成什么样,并不重要。

语法

Promise.race(iterable)

参数:一个可迭代对象(通常是数组),里面的元素可以是 Promise,也可以是普通值(普通值会被自动转换成已成功的 Promise)。

返回值:一个新的 Promise

示例代码

// 模拟一个延迟函数
function delay(ms, value, shouldReject = false) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldReject) {
reject(`任务 ${value} 失败`)
} else {
resolve(`任务 ${value} 完成`)
}
}, ms)
})
}
const task1 = delay(3000, 'A')
const task2 = delay(1000, 'B') // 这个最快完成
const task3 = delay(2000, 'C')
Promise.race([task1, task2, task3])
.then((result) => {
console.log('第一个完成的任务结果:', result)
})
.catch((error) => {
console.error('第一个完成的任务失败:', error)
})

运行效果(第一个完成的是成功的任务):

第一个完成的任务结果: 任务 B 完成

如果第一个完成的是失败的任务:

const task1 = delay(3000, 'A')
const task2 = delay(1000, 'B', true) // 最快完成,但失败
const task3 = delay(2000, 'C')

输出:

第一个完成的任务失败: 任务 B 失败

适用场景

Promise.any#

Promise.any()并行执行多个 Promise,并在第一个成功的 Promise 状态确定后,返回一个新的 Promise。 它会忽略所有失败的 Promise,直到有一个成功为止。 如果所有 Promise 都失败,则返回一个拒绝的 Promise,错误类型是 AggregateError(里面包含所有失败原因)。

你可以把它理解成“众人拾柴火焰高,只要有人成功就算成功”的模式。

语法

Promise.any(iterable)

示例代码

// 模拟一个延迟函数
function delay(ms, value, shouldReject = false) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldReject) {
reject(`任务 ${value} 失败`)
} else {
resolve(`任务 ${value} 完成`)
}
}, ms)
})
}
const task1 = delay(1000, 'A', true) // 失败
const task2 = delay(2000, 'B') // 成功(最先成功)
const task3 = delay(1500, 'C', true) // 失败
Promise.any([task1, task2, task3])
.then((result) => {
console.log('第一个成功的任务结果:', result)
})
.catch((error) => {
console.error('所有任务都失败:', error)
console.error('失败原因列表:', error.errors)
})

运行效果(第一个成功的任务是 B):

第一个成功的任务结果: 任务 B 完成

运行效果(所有任务都失败):

const task1 = delay(1000, 'A', true)
const task2 = delay(2000, 'B', true)
const task3 = delay(1500, 'C', true)

输出:

所有任务都失败: [AggregateError: All promises were rejected] {
[errors]: [ '任务 A 失败', '任务 B 失败', '任务 C 失败' ]
}
失败原因列表: [ '任务 A 失败', '任务 B 失败', '任务 C 失败' ]

适用场景

工具类#

这类方法的作用是直接构造一个 Promise 实例,或者把已有的值(不一定是 Promise)转换成 Promise,以便在 Promise 链中使用。

特点:

代表方法:

它们的关键词是:“直接得到一个 Promise”

Promise.resolve(value)#

将任意值包装成一个**已成功(fulfilled)**的 Promise。

特点

示例代码

Promise.resolve(42).then((value) => {
console.log('结果:', value) // 结果: 42
})
const p = Promise.resolve(Promise.resolve('已是 Promise'))
p.then((value) => {
console.log('结果:', value) // 结果: 已是 Promise
})

Promise.reject(reason)#

快速创建一个**已拒绝(rejected)**的 Promise。

特点

示例代码

Promise.reject('出错了').catch((reason) => {
console.error('捕获到错误:', reason) // 捕获到错误: 出错了
})

两个工具方法的适用场景

新提案#

这类方法是近年来在 ECMAScript 规范中新增或仍处于提案阶段的 Promise 静态方法,它们旨在补充现有 Promise API 的不足,让某些常见模式能用更简洁的方式实现。

特点:

代表方法:

Promise.withResolvers#

Promise.withResolvers() 是 ES2024 新增的静态方法,用于一次性创建一个 Promise,并同时获取它的 resolvereject 方法,方便在外部以命令式方式完成或拒绝该 Promise。可以把它视为标准化的 Deferred 模式,避免手写样板代码。

Deferred(延迟对象):一种常见的异步编程模式,在这个模式里,我们先创建一个 Promise,然后把它的 resolvereject 方法暴露出来,让外部代码在合适的时机去完成(resolve)或拒绝(reject)这个 Promise。

在它出现之前,我们通常这样写:

// 传统 Deferred 写法:需要先声明外部变量再赋值
let resolveFn, rejectFn
const p = new Promise((resolve, reject) => {
resolveFn = resolve
rejectFn = reject
})
// 之后在合适时机调用 resolveFn()/rejectFn()

有了 withResolvers(),可以直接一行拿到 { promise, resolve, reject }

语法

const { promise, resolve, reject } = Promise.withResolvers()

讲到这里,肯定很多同学会有这样的疑问 🤔

以前 new Promise() 里那个函数是“干活的地方”,现在 Promise.withResolvers() 一下子就把 promiseresolvereject 都给了我,那原来写异步任务的地方去哪了?

举个例子:

如果是以前的写法:

const p = new Promise((resolve, reject) => {
// 这里就是干活的地方
setTimeout(() => {
resolve('完成了')
}, 1000)
})

这里的 (resolve, reject) => { ... } 构造函数内部是同步执行的,常见做法是:

那么用 withResolvers 后,异步任务该写在哪里呢?

实际上,Promise.withResolvers() 不帮你执行异步任务,它只是先给你一个空的 Promise 和它的控制按钮(resolvereject)。所以你要做异步任务,直接写在外面就行,等任务结束时用 resolvereject 去改变 Promise 的状态。

例如:

const { promise, resolve, reject } = Promise.withResolvers()
// 干活的地方可以放在这里(构造器外部),甚至在别的函数里
setTimeout(() => {
resolve('完成了') // 1 秒后完成 Promise
}, 1000)
// 监听结果
promise.then(console.log)

这样做的好处:

  1. 解耦:创建 Promise 和执行任务分开,不必绑死在构造函数里面。
  2. 灵活:resolve / reject 可以传给别的模块、事件回调、外部函数,在任何时机、任何地方去结束这个 Promise。
  3. 适合桥接事件/回调:以前 new Promise 只能在构造时写好逻辑,现在你可以先创建 Promise,然后等事件真正发生时才调用 resolvereject

Promise.try#

Promise.try() 目前还处于 TC39 提案阶段(Stage 1),尚未进入 ECMAScript 正式标准。它的目标是提供一种更简洁的方式来统一处理同步代码和异步代码中的异常,让它们都以 Promise 的形式返回结果。

在没有 Promise.try() 之前,我们经常会用 new Promise()Promise.resolve().then(...) 来包装可能抛出错误的代码,这样无论是同步错误还是异步错误,都能进入 Promise 链的 .catch()

有了 Promise.try(),这种写法会更简洁直观。

我们来看一个具体的案例,假设我们有两个操作:

  1. 同步操作:读取一个本地配置文件并解析 JSON
  2. 异步操作:去远程服务器拉取数据

这两个操作都有可能出错:

// 同步解析 JSON
function readConfig() {
// 假设文件内容是错误的 JSON 格式,会抛出 SyntaxError
const content = '{ invalid json }'
return JSON.parse(content)
}
// 异步请求数据
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => reject('网络错误'), 1000)
})
}
try {
// 同步调用,必须用 try/catch 捕获
const config = readConfig()
// 异步调用,必须用 Promise.catch 处理
fetchData()
.then((data) => console.log('数据:', data))
.catch((err) => console.error('异步出错:', err))
} catch (err) {
console.error('同步出错:', err.message)
}

问题

后面就出现了 try...catch 的一种基于 Promise 化的改进版,如下:

Promise.resolve().then(() => { ... })

这种方式,把同步代码包装成 Promise,这样抛错时会走到 .catch(),就不需要额外写 try...catch 了。

例如上面的例子,我们就可以进行如下的改进

// 同步解析 JSON
function readConfig() {
// 假设文件内容是错误的 JSON 格式,会抛出 SyntaxError
const content = '{ invalid json }'
return JSON.parse(content)
}
// 异步请求数据
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => reject('网络错误'), 1000)
})
}
// 用 Promise.resolve() 包装,让同步错误也能走到 .catch()
Promise.resolve()
.then(() => {
const config = readConfig() // 同步执行,如果抛错,直接进入 catch
return fetchData() // 异步 Promise 失败也会进入同一个 catch
})
.then((data) => {
console.log('数据:', data)
})
.catch((err) => {
console.error('捕获到错误:', err.message || err)
})

改进点

接下来我们来看一下 Promise.try(),先来看一下基本的语法:

语法

Promise.try(fn)

Promise.try(fn) 就是帮你做这件事:

有了 Promise.try() 之后,写法会更直接。接下来我们还是使用 Promise.try() 来重构上面的例子:

// 同步解析 JSON
function readConfig() {
// 假设文件内容是错误的 JSON 格式,会抛出 SyntaxError
const content = '{ invalid json }'
return JSON.parse(content)
}
// 异步请求数据
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => reject('网络错误'), 1000)
})
}
// 用 Promise.try() 统一处理同步和异步错误
Promise.try(() => {
const config = readConfig() // 同步执行,如果抛错,直接进入 catch
return fetchData() // 异步 Promise 失败也会进入同一个 catch
})
.then((data) => {
console.log('数据:', data)
})
.catch((err) => {
console.error('捕获到错误:', err.message || err)
})

写在最后#

Promise 的这些静态方法,可以看作是对异步任务的“批量管理工具箱”。

在实际开发中,合理选择这些方法可以让异步代码更加优雅、可控:

掌握这些方法,并在合适的场景中灵活运用,你的异步任务管理会更加高效,代码也更具可维护性。