在掌握 Promise 基础后,来看更多静态方法和进阶用法。
Promise.all()#
等待所有 Promise 完成,任意一个失败就立即失败:
const p1 = Promise.resolve(1)const p2 = Promise.resolve(2)const p3 = Promise.resolve(3)
Promise.all([p1, p2, p3]).then((values) => { console.log(values) // [1, 2, 3](顺序与传入一致)})
// 有一个失败就全部失败const p4 = Promise.reject(new Error('失败'))
Promise.all([p1, p2, p4]).catch((error) => { console.log(error.message) // '失败'})实际应用#
// 并行请求多个接口async function fetchAllData() { const [users, posts, comments] = await Promise.all([ fetch('/api/users').then((r) => r.json()), fetch('/api/posts').then((r) => r.json()), fetch('/api/comments').then((r) => r.json()), ])
return { users, posts, comments }}
// 批量处理async function processItems(items) { const results = await Promise.all(items.map((item) => processItem(item))) return results}🔶 注意事项#
// 空数组立即 resolvePromise.all([]).then((v) => console.log(v)) // []
// 非 Promise 值会被自动包装Promise.all([1, 2, 3]).then((v) => console.log(v)) // [1, 2, 3]
// 一旦有一个失败,不会等待其他const slow = new Promise((r) => setTimeout(() => r('slow'), 3000))const fast = Promise.reject(new Error('fast'))
Promise.all([slow, fast]).catch((e) => console.log(e.message)) // 'fast'(不会等待 slow)Promise.race()#
返回最先完成(无论成功还是失败)的结果:
const p1 = new Promise((r) => setTimeout(() => r('p1'), 100))const p2 = new Promise((r) => setTimeout(() => r('p2'), 200))
Promise.race([p1, p2]).then((value) => console.log(value)) // 'p1'
// 超时控制function fetchWithTimeout(url, timeout = 5000) { return Promise.race([ fetch(url), new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), timeout) ), ])}空数组永远 pending#
Promise.race([]).then(() => { console.log('永远不会执行')})Promise.allSettled()#
ES2020 新增,等待所有 Promise 完成,无论成功失败:
const p1 = Promise.resolve(1)const p2 = Promise.reject(new Error('失败'))const p3 = Promise.resolve(3)
Promise.allSettled([p1, p2, p3]).then((results) => { console.log(results) // [ // { status: 'fulfilled', value: 1 }, // { status: 'rejected', reason: Error: 失败 }, // { status: 'fulfilled', value: 3 } // ]})实际应用#
// 批量请求,即使部分失败也要继续async function fetchMultiple(urls) { const results = await Promise.allSettled( urls.map((url) => fetch(url).then((r) => r.json())) )
const successful = results .filter((r) => r.status === 'fulfilled') .map((r) => r.value)
const failed = results .filter((r) => r.status === 'rejected') .map((r) => r.reason)
return { successful, failed }}Promise.any()#
ES2021 新增,返回第一个成功的结果:
const p1 = Promise.reject(new Error('失败1'))const p2 = new Promise((r) => setTimeout(() => r('成功'), 100))const p3 = Promise.reject(new Error('失败2'))
Promise.any([p1, p2, p3]).then((value) => console.log(value)) // '成功'
// 全部失败时抛出 AggregateErrorPromise.any([ Promise.reject(new Error('1')), Promise.reject(new Error('2')),]).catch((error) => { console.log(error instanceof AggregateError) // true console.log(error.errors) // [Error: 1, Error: 2]})实际应用#
// 从多个源获取数据,使用最快的async function fetchFromAnyMirror(mirrors) { try { return await Promise.any( mirrors.map((url) => fetch(url).then((r) => r.json())) ) } catch (error) { throw new Error('所有镜像都失败') }}错误处理模式#
统一错误处理#
class APIError extends Error { constructor(message, status) { super(message) this.name = 'APIError' this.status = status }}
async function fetchAPI(url) { const response = await fetch(url)
if (!response.ok) { throw new APIError(`请求失败: ${response.statusText}`, response.status) }
return response.json()}
// 使用fetchAPI('/api/users') .then((data) => console.log(data)) .catch((error) => { if (error instanceof APIError) { console.log(`API 错误 (${error.status}): ${error.message}`) } else { console.log('未知错误:', error) } })try-catch 模式#
async function safeExecute(fn) { try { const result = await fn() return { success: true, data: result } } catch (error) { return { success: false, error } }}
const result = await safeExecute(() => fetchAPI('/api/users'))
if (result.success) { console.log(result.data)} else { console.log('错误:', result.error)}Go 风格错误处理#
function to(promise) { return promise.then((data) => [null, data]).catch((err) => [err, null])}
async function example() { const [err, data] = await to(fetchAPI('/api/users'))
if (err) { console.log('错误:', err) return }
console.log('数据:', data)}并发控制#
限制并发数#
async function asyncPool(limit, items, fn) { const results = [] const executing = new Set()
for (const [index, item] of items.entries()) { const promise = fn(item, index).then((result) => { executing.delete(promise) return result })
results.push(promise) executing.add(promise)
if (executing.size >= limit) { await Promise.race(executing) } }
return Promise.all(results)}
// 使用:同时最多 3 个并发请求const urls = ['url1', 'url2', 'url3', 'url4', 'url5']const results = await asyncPool(3, urls, (url) => fetch(url))队列模式#
class PromiseQueue { constructor(concurrency = 1) { this.concurrency = concurrency this.running = 0 this.queue = [] }
add(fn) { return new Promise((resolve, reject) => { this.queue.push({ fn, resolve, reject }) this.run() }) }
run() { while (this.running < this.concurrency && this.queue.length > 0) { const { fn, resolve, reject } = this.queue.shift() this.running++
fn() .then(resolve) .catch(reject) .finally(() => { this.running-- this.run() }) } }}
// 使用const queue = new PromiseQueue(2)
for (const url of urls) { queue.add(() => fetch(url)).then((response) => console.log('完成:', url))}Promise 实现细节#
微任务#
Promise 回调在微任务队列执行:
console.log('1')
Promise.resolve().then(() => { console.log('2')})
console.log('3')
// 输出顺序: 1, 3, 2值穿透#
Promise.resolve(1) .then() // 没有回调函数 .then(2) // 非函数参数被忽略 .then((v) => console.log(v)) // 1(值穿透)Promise 链的错误恢复#
Promise.reject(new Error('失败')) .catch((error) => { console.log('捕获:', error.message) return '恢复的值' // catch 返回值会被传递 }) .then((value) => { console.log('继续:', value) // '恢复的值' })方法对比#
| 方法 | 版本 | 行为 |
|---|---|---|
| Promise.all() | ES6 | 全部成功或任一失败 |
| Promise.race() | ES6 | 返回最先完成的 |
| Promise.allSettled() | ES2020 | 等待全部完成 |
| Promise.any() | ES2021 | 返回第一个成功的 |
// 对比const p1 = Promise.resolve(1)const p2 = Promise.reject(2)const p3 = Promise.resolve(3)
Promise.all([p1, p2, p3]) // reject 2Promise.race([p1, p2, p3]) // resolve 1Promise.allSettled([p1, p2, p3]) // resolve [...]Promise.any([p1, p2, p3]) // resolve 1Promise 是 JavaScript 异步编程的核心,熟练掌握各种方法和模式对于编写健壮的异步代码至关重要。