Promise 的链式调用
Promise 的链式调用是其最强大的特性之一,它允许我们以更优雅的方式处理多个连续的异步操作。链式调用的核心在于then()方法会返回一个新的 Promise 对象。
链式调用的基本原理
当调用 Promise 的then()方法时,它会返回一个新的 Promise 对象,这个新 Promise 的状态和值由then()方法的回调函数决定:
javascript
// 基本链式调用示例
fetch('/api/user/1')
.then((response) => response.json()) // 返回一个新的Promise
.then((user) => {
console.log('用户信息:', user);
return fetch(`/api/posts/${user.id}`); // 返回另一个Promise
})
.then((response) => response.json()) // 处理上一个Promise的结果
.then((posts) => {
console.log('用户文章:', posts);
})
.catch((error) => {
console.error('发生错误:', error);
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
链式调用中的值传递
在链式调用中,每个then()回调函数的返回值会成为下一个then()回调函数的参数:
javascript
Promise.resolve(5)
.then((value) => {
console.log(value); // 输出: 5
return value * 2; // 返回10
})
.then((value) => {
console.log(value); // 输出: 10
return value + 3; // 返回13
})
.then((value) => {
console.log(value); // 输出: 13
});1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
返回 Promise 对象
当then()回调函数返回一个 Promise 对象时,链式调用会等待这个 Promise 解决后继续执行:
javascript
function getUser(id) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ id, name: `用户${id}` });
}, 1000);
});
}
function getUserPosts(userId) {
return new Promise((resolve) => {
setTimeout(() => {
resolve([`文章1-用户${userId}`, `文章2-用户${userId}`]);
}, 1000);
});
}
getUser(1)
.then((user) => {
console.log('获取到用户:', user);
return getUserPosts(user.id); // 返回Promise
})
.then((posts) => {
console.log('获取到文章:', posts);
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
错误传播
在链式调用中,错误会沿着链向下传播,直到被第一个.catch()捕获:
javascript
Promise.resolve()
.then(() => {
throw new Error('第一个错误');
})
.then(() => {
console.log('这里不会执行');
})
.then(() => {
console.log('这里也不会执行');
})
.catch((error) => {
console.error('捕获到错误:', error.message); // 输出: 捕获到错误: 第一个错误
});1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
多个 catch 的使用
可以在链式调用中添加多个.catch(),每个.catch()可以处理前一个阶段产生的错误:
javascript
Promise.resolve()
.then(() => {
throw new Error('第一个错误');
})
.catch((error) => {
console.error('第一个catch:', error.message);
// 如果不返回一个被拒绝的Promise,链会继续执行
return '恢复后的值';
})
.then((value) => {
console.log('继续执行:', value); // 输出: 继续执行: 恢复后的值
throw new Error('第二个错误');
})
.catch((error) => {
console.error('第二个catch:', error.message); // 输出: 第二个catch: 第二个错误
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
then 的第二个参数
then()方法可以接收第二个参数作为错误回调,但通常更推荐使用.catch():
javascript
// 使用then的第二个参数处理错误
Promise.resolve().then(
() => {
throw new Error('发生错误');
},
(error) => {
console.error('在then中捕获错误:', error.message);
}
);
// 使用catch处理错误(推荐)
Promise.resolve()
.then(() => {
throw new Error('发生错误');
})
.catch((error) => {
console.error('在catch中捕获错误:', error.message);
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
链式调用的最佳实践
保持链式调用的简洁性
javascript// 不推荐:过深的嵌套 fetch('/api/user').then((response) => { return response.json().then((user) => { return fetch(`/api/posts/${user.id}`).then((response) => { return response.json().then((posts) => { console.log(posts); }); }); }); }); // 推荐:扁平化的链式调用 fetch('/api/user') .then((response) => response.json()) .then((user) => fetch(`/api/posts/${user.id}`)) .then((response) => response.json()) .then((posts) => console.log(posts));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17始终添加错误处理
javascript// 不推荐:缺少错误处理 fetch('/api/data') .then((response) => response.json()) .then((data) => console.log(data)); // 推荐:添加错误处理 fetch('/api/data') .then((response) => response.json()) .then((data) => console.log(data)) .catch((error) => console.error('请求失败:', error));1
2
3
4
5
6
7
8
9
10合理使用 Promise.all()处理并行操作
javascript// 获取用户信息和文章列表并行执行 Promise.all([ fetch('/api/user').then((response) => response.json()), fetch('/api/posts').then((response) => response.json()) ]) .then(([user, posts]) => { console.log('用户:', user); console.log('文章:', posts); }) .catch((error) => console.error('请求失败:', error));1
2
3
4
5
6
7
8
9
10使用 async/await 简化链式调用
javascript// 传统链式调用 fetch('/api/user') .then((response) => response.json()) .then((user) => fetch(`/api/posts/${user.id}`)) .then((response) => response.json()) .then((posts) => console.log(posts)) .catch((error) => console.error('请求失败:', error)); // 使用async/await(更简洁) async function fetchUserPosts() { try { const userResponse = await fetch('/api/user'); const user = await userResponse.json(); const postsResponse = await fetch(`/api/posts/${user.id}`); const posts = await postsResponse.json(); console.log(posts); } catch (error) { console.error('请求失败:', error); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Promise 的链式调用为异步编程提供了强大而灵活的工具,通过合理使用这些模式,可以编写出清晰、可维护的异步代码。

