Promise 的链式调用是 Promise 最强大的特性之一,它允许我们以优雅的方式处理多个异步操作,避免了回调地狱的问题。
基本概念
Promise 链式调用是指通过 .then() 方法返回一个新的 Promise,从而可以连续调用多个 .then() 方法。每个 .then() 方法接收前一个 Promise 的结果作为参数,并返回一个新的 Promise。
链式调用的工作原理
核心机制
.then()方法总是返回一个新的 Promise- 前一个
.then()的返回值会传递给下一个.then() - 如果返回的是 Promise,会等待其完成后再传递结果
- 错误会沿着链向下传递,直到被
.catch()捕获
示例代码
javascriptfetch('/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. 返回普通值
javascriptPromise.resolve(1) .then(value => value + 1) .then(value => value * 2) .then(value => console.log(value)); // 输出: 4
2. 返回 Promise
javascriptPromise.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)
javascriptPromise.resolve(1) .then(value => { console.log(value); // 输出: 1 // 不返回任何值,相当于返回 undefined }) .then(value => console.log(value)); // 输出: undefined
4. 抛出错误
javascriptPromise.resolve(1) .then(value => { throw new Error('出错了'); }) .catch(error => { console.error(error.message); // 输出: 出错了 return '恢复后的值'; }) .then(value => console.log(value)); // 输出: 恢复后的值
错误处理机制
错误传递
javascriptPromise.resolve() .then(() => { throw new Error('第一个错误'); }) .then(() => { console.log('这行不会执行'); }) .catch(error => { console.error('捕获错误:', error.message); return '继续执行'; }) .then(value => { console.log(value); // 输出: 继续执行 });
多个 catch
javascriptPromise.resolve() .then(() => { throw new Error('错误'); }) .catch(error => { console.error('第一个 catch:', error.message); throw new Error('新错误'); }) .catch(error => { console.error('第二个 catch:', error.message); });
Promise 链式调用 vs 回调地狱
回调地狱(不推荐)
javascriptfetch('/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 链式调用(推荐)
javascriptfetch('/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
javascriptPromise.resolve() .then(() => console.log('执行操作')) .catch(error => console.error(error)) .finally(() => console.log('清理资源'));
3. 错误处理要全面
javascriptPromise.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. 如何在链中传递多个值?
javascriptPromise.all([promise1, promise2]) .then(([result1, result2]) => { console.log(result1, result2); });
2. 如何在链中跳过某些步骤?
javascriptPromise.resolve() .then(() => { if (shouldSkip) { return Promise.reject('skip'); } return doSomething(); }) .catch(error => { if (error === 'skip') { return '跳过的结果'; } throw error; }) .then(result => console.log(result));
3. 如何在链中添加日志?
javascriptPromise.resolve(1) .tap(value => console.log('当前值:', value)) .then(value => value + 1) .tap(value => console.log('新值:', value));
与 async/await 的对比
Promise 链式调用
javascriptfetch('/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(更易读)
javascriptasync 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 链式调用的语法糖,让异步代码看起来更像同步代码,提高了代码的可读性。