乐闻世界logo
搜索文章和话题

如何理解 Promise 的链式调用?

2月22日 14:07

Promise 的链式调用是 Promise 最强大的特性之一,它允许我们以优雅的方式处理多个异步操作,避免了回调地狱的问题。

基本概念

Promise 链式调用是指通过 .then() 方法返回一个新的 Promise,从而可以连续调用多个 .then() 方法。每个 .then() 方法接收前一个 Promise 的结果作为参数,并返回一个新的 Promise。

链式调用的工作原理

核心机制

  1. .then() 方法总是返回一个新的 Promise
  2. 前一个 .then() 的返回值会传递给下一个 .then()
  3. 如果返回的是 Promise,会等待其完成后再传递结果
  4. 错误会沿着链向下传递,直到被 .catch() 捕获

示例代码

javascript
fetch('/api/user') .then(response => response.json()) .then(user => { console.log('用户信息:', user); return fetch(`/api/posts/${user.id}`); }) .then(response => response.json()) .then(posts => { console.log('用户文章:', posts); return posts; }) .catch(error => { console.error('发生错误:', error); });

链式调用的返回值处理

1. 返回普通值

javascript
Promise.resolve(1) .then(value => value + 1) .then(value => value * 2) .then(value => console.log(value)); // 输出: 4

2. 返回 Promise

javascript
Promise.resolve(1) .then(value => { return Promise.resolve(value + 1); }) .then(value => { return new Promise(resolve => { setTimeout(() => resolve(value * 2), 1000); }); }) .then(value => console.log(value)); // 输出: 4

3. 不返回值(返回 undefined)

javascript
Promise.resolve(1) .then(value => { console.log(value); // 输出: 1 // 不返回任何值,相当于返回 undefined }) .then(value => console.log(value)); // 输出: undefined

4. 抛出错误

javascript
Promise.resolve(1) .then(value => { throw new Error('出错了'); }) .catch(error => { console.error(error.message); // 输出: 出错了 return '恢复后的值'; }) .then(value => console.log(value)); // 输出: 恢复后的值

错误处理机制

错误传递

javascript
Promise.resolve() .then(() => { throw new Error('第一个错误'); }) .then(() => { console.log('这行不会执行'); }) .catch(error => { console.error('捕获错误:', error.message); return '继续执行'; }) .then(value => { console.log(value); // 输出: 继续执行 });

多个 catch

javascript
Promise.resolve() .then(() => { throw new Error('错误'); }) .catch(error => { console.error('第一个 catch:', error.message); throw new Error('新错误'); }) .catch(error => { console.error('第二个 catch:', error.message); });

Promise 链式调用 vs 回调地狱

回调地狱(不推荐)

javascript
fetch('/api/user', (error, response) => { if (error) { console.error(error); return; } response.json((error, user) => { if (error) { console.error(error); return; } fetch(`/api/posts/${user.id}`, (error, response) => { if (error) { console.error(error); return; } response.json((error, posts) => { if (error) { console.error(error); return; } console.log(posts); }); }); }); });

Promise 链式调用(推荐)

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));

最佳实践

1. 保持链的扁平

javascript
// 不推荐:嵌套 Promise Promise.resolve() .then(() => { return Promise.resolve().then(() => { return Promise.resolve().then(() => { console.log('嵌套太深'); }); }); }); // 推荐:扁平链式 Promise.resolve() .then(() => {}) .then(() => {}) .then(() => console.log('扁平清晰'));

2. 合理使用 finally

javascript
Promise.resolve() .then(() => console.log('执行操作')) .catch(error => console.error(error)) .finally(() => console.log('清理资源'));

3. 错误处理要全面

javascript
Promise.resolve() .then(data => { // 处理数据 return processData(data); }) .catch(error => { // 处理错误 console.error('处理失败:', error); // 可以返回默认值或重新抛出错误 return defaultValue; });

4. 避免在 then 中创建不必要的 Promise

javascript
// 不推荐 Promise.resolve(1) .then(value => { return new Promise(resolve => { resolve(value + 1); }); }); // 推荐 Promise.resolve(1) .then(value => value + 1);

常见问题

1. 如何在链中传递多个值?

javascript
Promise.all([promise1, promise2]) .then(([result1, result2]) => { console.log(result1, result2); });

2. 如何在链中跳过某些步骤?

javascript
Promise.resolve() .then(() => { if (shouldSkip) { return Promise.reject('skip'); } return doSomething(); }) .catch(error => { if (error === 'skip') { return '跳过的结果'; } throw error; }) .then(result => console.log(result));

3. 如何在链中添加日志?

javascript
Promise.resolve(1) .tap(value => console.log('当前值:', value)) .then(value => value + 1) .tap(value => console.log('新值:', value));

与 async/await 的对比

Promise 链式调用

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(更易读)

javascript
async function fetchPosts() { 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); } }

async/await 本质上是 Promise 链式调用的语法糖,让异步代码看起来更像同步代码,提高了代码的可读性。

标签:Promise