Promise 的方法
Promise 规范经历了多个发展阶段,从最初的 Promise/A+社区规范到后来的 ECMAScript 标准。Promise/A+规范主要定义了 Promise 的基本行为和then()方法的核心实现,而 ECMAScript 标准在此基础上添加了更多实用的静态方法和实例方法。
除了基本的then()方法外,Promise 还提供了其他一些实用的静态方法和实例方法,这些方法可以帮助我们更灵活地处理异步操作。
静态方法
Promise.resolve()
Promise.resolve()方法返回一个以给定值解析后的 Promise 对象。
- 如果这个值是一个 Promise,那么将返回这个 Promise;
- 如果这个值是 thenable(即带有
then方法),Promise 会执行它的 then 方法; - 否则返回的 Promise 会以这个值兑现。
// 1. 传入普通值
const promise1 = Promise.resolve(42);
promise1.then((value) => console.log(value)); // 输出: 42
// 2. 传入Promise对象
const originalPromise = new Promise((resolve) => {
setTimeout(() => resolve('原始Promise'), 1000);
});
const promise2 = Promise.resolve(originalPromise);
promise2.then((value) => console.log(value)); // 1秒后输出: 原始Promise
// 3. 传入thenable对象
const thenable = {
then: function (resolve) {
resolve('这是一个thenable对象');
}
};
const promise3 = Promise.resolve(thenable);
promise3.then((value) => console.log(value)); // 输出: 这是一个thenable对象2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Promise.reject()
Promise.reject()方法返回一个带有拒绝原因的 Promise 对象。
const promise = Promise.reject(new Error('出错了'));
promise.catch((error) => console.log(error.message)); // 输出: 出错了
// 与throw new Error()效果相同
const promise2 = new Promise((resolve, reject) => {
reject(new Error('出错了'));
});
promise2.catch((error) => console.log(error.message)); // 输出: 出错了2
3
4
5
6
7
8
Promise.all()
Promise.all()方法接收一个 Promise 可迭代对象(通常是数组),并返回一个新的 Promise。
- 所有 Promise 成功解决时返回包含所有解决值的数组
- 任一 Promise 被拒绝时立即拒绝,拒绝原因为第一个被拒绝的 Promise 的拒绝原因
// 所有Promise都成功
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve) => setTimeout(() => resolve('foo'), 1000));
const promise3 = Promise.resolve(42);
Promise.all([promise1, promise2, promise3])
.then((values) => {
console.log(values); // 输出: [3, "foo", 42]
})
.catch((error) => {
console.error('至少有一个Promise被拒绝:', error);
});
// 有一个Promise失败
const promise4 = Promise.resolve(3);
const promise5 = Promise.reject(new Error('失败'));
const promise6 = Promise.resolve(42);
Promise.all([promise4, promise5, promise6])
.then((values) => {
console.log(values); // 不会执行
})
.catch((error) => {
console.error('至少有一个Promise被拒绝:', error.message); // 输出: 失败
});2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Promise.allSettled()
Promise.allSettled()方法返回一个在所有给定的 Promise 都已经解决或拒绝后解决(settled)的 Promise,并带有一个对象数组,每个对象表示对应的 Promise 结果。
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve) => setTimeout(() => resolve('foo'), 1000));
const promise3 = Promise.reject(new Error('失败'));
Promise.allSettled([promise1, promise2, promise3]).then((results) => {
results.forEach((result, i) => {
if (result.status === 'fulfilled') {
console.log(`Promise ${i} 成功:`, result.value);
} else {
console.log(`Promise ${i} 失败:`, result.reason.message);
}
});
});
/*
输出:
Promise 0 成功: 3
Promise 1 成功: foo
Promise 2 失败: 失败
*/2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Promise.race()
Promise.race()方法返回一个 Promise,一旦迭代器中的某个 Promise 解决或拒绝,返回的 Promise 就会解决或拒绝。
const promise1 = new Promise((resolve) => setTimeout(() => resolve('one'), 500));
const promise2 = new Promise((resolve) => setTimeout(() => resolve('two'), 100));
Promise.race([promise1, promise2]).then((value) => {
console.log(value); // 输出: "two" (因为它更快)
});
// 使用Promise.race实现超时
function fetchWithTimeout(url, timeout = 5000) {
return Promise.race([
fetch(url),
new Promise((_, reject) => setTimeout(() => reject(new Error('请求超时')), timeout))
]);
}
fetchWithTimeout('/api/data')
.then((response) => response.json())
.then((data) => console.log('数据:', data))
.catch((error) => console.error('错误:', error.message));2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Promise.any()
Promise.any()方法接收一个 Promise 可迭代对象,只要其中的任何一个 Promise 成功,就返回那个成功的 Promise 的值。如果所有 Promise 都失败,则返回一个失败的 Promise 和 AggregateError 对象(包含所有失败信息)。
const promise1 = Promise.reject(new Error('失败1'));
const promise2 = Promise.reject(new Error('失败2'));
const promise3 = Promise.resolve('成功');
Promise.any([promise1, promise2, promise3])
.then((value) => {
console.log(value); // 输出: "成功"
})
.catch((error) => {
console.error('所有Promise都失败了:', error);
});
// 所有Promise都失败的情况
Promise.any([promise1, promise2])
.then((value) => {
console.log(value); // 不会执行
})
.catch((error) => {
console.error('所有Promise都失败了:', error.errors); // 输出所有错误信息
});2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Promise.withResolvers()
这是一个较新的方法(ES2023),它创建了一个 Promise 对象和两个函数:一个用于解决 Promise,一个用于拒绝 Promise。
const { promise, resolve, reject } = Promise.withResolvers();
// 在稍后的某个时刻解决或拒绝Promise
setTimeout(() => {
resolve('延迟解决');
}, 1000);
promise.then((value) => {
console.log(value); // 1秒后输出: "延迟解决"
});
// 传统方式实现相同功能
let resolve, reject;
const promise2 = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
setTimeout(() => {
resolve('延迟解决');
}, 1000);
promise2.then((value) => {
console.log(value); // 1秒后输出: "延迟解决"
});2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
实例方法
Promise.prototype.then()
then()方法是 Promise 的核心方法,用于注册 Promise 解决和拒绝时的回调函数。它返回一个新的 Promise,允许链式调用。
const promise = new Promise((resolve) => {
setTimeout(() => resolve('成功'), 1000);
});
promise
.then((value) => {
console.log(value); // 输出: "成功"
return value + ' - 处理后';
})
.then((newValue) => {
console.log(newValue); // 输出: "成功 - 处理后"
});2
3
4
5
6
7
8
9
10
11
12
Promise.prototype.catch()
catch()方法是then(undefined, onRejected)的语法糖,专门用于处理 Promise 被拒绝的情况。
// 使用catch
fetch('/api/data')
.then((response) => response.json())
.catch((error) => {
console.error('请求失败:', error);
});
// 等同于
fetch('/api/data')
.then((response) => response.json())
.then(undefined, (error) => {
console.error('请求失败:', error);
});2
3
4
5
6
7
8
9
10
11
12
13
Promise.prototype.finally()
finally()方法在 Promise 结束时,无论结果是 fulfilled 还是 rejected,都会执行指定的回调函数。它返回一个 Promise,其行为与原 Promise 基本一致,但在原 Promise 解决后执行回调。通常用于清理操作,如隐藏加载指示器。
// 基本用法
fetch('/api/data')
.then((response) => response.json())
.then((data) => {
console.log('获取数据成功:', data);
})
.catch((error) => {
console.error('获取数据失败:', error);
})
.finally(() => {
console.log('请求完成,无论成功或失败');
// 可以在这里隐藏加载指示器
hideLoadingIndicator();
});
// 实际应用场景:加载状态管理
let isLoading = true;
fetch('/api/data')
.then((response) => response.json())
.then((data) => {
console.log('数据:', data);
})
.catch((error) => {
console.error('错误:', error);
})
.finally(() => {
isLoading = false;
console.log('加载完成');
});
// finally方法的返回值
Promise.resolve('成功')
.finally(() => {
console.log('清理操作');
return 'finally的返回值'; // 这个返回值会被忽略
})
.then((value) => {
console.log(value); // 输出: "成功",而不是"finally的返回值"
});
// finally中抛出错误
Promise.resolve('成功')
.finally(() => {
console.log('清理操作');
throw new Error('清理时出错'); // 这个错误会传递到后续的catch
})
.catch((error) => {
console.error('捕获到错误:', error.message); // 输出: 捕获到错误: 清理时出错
});2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
实际应用场景
并发请求处理
javascript// 并行获取多个资源 async function fetchUserData(userId) { const [user, posts, comments] = await Promise.all([ fetch(`/api/users/${userId}`).then((res) => res.json()), fetch(`/api/users/${userId}/posts`).then((res) => res.json()), fetch(`/api/users/${userId}/comments`).then((res) => res.json()) ]); return { user, posts, comments }; }1
2
3
4
5
6
7
8
9
10请求超时处理
javascript// 使用Promise.race实现超时控制 function fetchWithTimeout(url, timeout = 5000) { return Promise.race([ fetch(url), new Promise((_, reject) => setTimeout(() => reject(new Error('请求超时')), timeout)) ]); }1
2
3
4
5
6
7重试机制
javascript// 实现请求重试机制 function fetchWithRetry(url, options = {}, retries = 3) { return fetch(url, options).catch((error) => { if (retries <= 0) throw error; console.log(`请求失败,剩余重试次数: ${retries}`); return fetchWithRetry(url, options, retries - 1); }); }1
2
3
4
5
6
7
8批量处理与错误收集
javascript// 使用Promise.allSettled处理批量操作,收集所有错误 async function processBatch(items, processor) { const results = await Promise.allSettled(items.map((item) => processor(item))); const successful = results .filter((result) => result.status === 'fulfilled') .map((result) => result.value); const failed = results .filter((result) => result.status === 'rejected') .map((result) => result.reason); return { successful, failed }; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
这些 Promise 方法提供了强大的工具来处理各种异步场景,从简单的单个异步操作到复杂的并发控制和错误处理。掌握这些方法可以帮助我们编写更清晰、更健壮的异步代码。

