有一次,我需要同时调用多个接口来获取数据。为了提高效率,我使用了 Promise.all 方法。代码部署后,一切看起来都很完美,我觉得自己解决了一个大问题。
但很快,问题出现了。当其中一个接口偶尔失败时,整个页面都会崩溃。用户看到的是一个错误提示,而不是他们需要的数据。这让我意识到,我需要找到一个更好的解决方案。
在我的项目中,有一个数据面板需要从多个服务获取信息:
const [user, orders, notifications] = await Promise.all([
getUser(),
getOrders(),
getNotifications(),
]);
在大多数情况下,这段代码运行得很好。但是,只要其中任何一个请求失败,整个 Promise.all 就会立即停止,并抛出错误。这意味着即使其他请求都成功了,用户也看不到任何数据。
经过研究,我发现了 Promise.allSettled 这个方法。它与 Promise.all 的不同之处在于,它会等待所有请求都完成,不管它们是成功还是失败。
const results = await Promise.allSettled([
getUser(),
getOrders(),
getNotifications(),
]);
// 处理结果
results.forEach(result => {
if (result.status === 'fulfilled') {
// 请求成功
console.log('成功获取数据:', result.value);
} else {
// 请求失败
console.log('获取数据失败:', result.reason);
}
});
使用 Promise.allSettled 后,我获得了几个重要的优势:
显示部分数据:即使某些请求失败,成功的数据仍然可以显示给用户
明确错误位置:可以清楚地知道是哪个模块出了问题
针对性重试:只重新请求失败的接口,而不是全部重试
在实际项目中,你可以这样处理:
async function loadDashboardData() {
const results = await Promise.allSettled([
getUserInfo(),
getOrderList(),
getNotificationCount(),
getRecommendations()
]);
const data = {};
const errors = [];
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
// 根据索引确定是哪个请求的数据
switch(index) {
case 0: data.user = result.value; break;
case 1: data.orders = result.value; break;
case 2: data.notifications = result.value; break;
case 3: data.recommendations = result.value; break;
}
} else {
errors.push({index, error: result.reason});
}
});
return {data, errors};
}
对于失败的请求,你可以选择性地重试:
async function loadDataWithRetry() {
let results = await Promise.allSettled(requests);
// 找出失败的请求
const failedRequests = results
.map((result, index) => ({result, index}))
.filter(item => item.result.status === 'rejected')
.map(item => requests[item.index]);
// 只重试失败的请求
if (failedRequests.length > 0) {
const retryResults = await Promise.allSettled(failedRequests);
// 合并重试结果...
}
return results;
}
根据我的经验,这两种方法各有适用场景:
使用 Promise.all 的情况:
用户登录验证(所有步骤都必须成功)
订单支付流程(每个环节都不能出错)
数据提交(所有操作都要完成)
使用 Promise.allSettled 的情况:
数据面板显示(部分数据可用就好)
侧边栏小工具(某些内容可以缺失)
推荐内容加载(没有推荐也能正常使用)
区分重要程度:把关键数据和次要数据分开处理
提供备用方案:对于失败的内容,显示占位符或默认内容
用户提示:告诉用户哪些内容暂时不可用
错误记录:记录失败的原因,便于后续优化
async function loadPageData() {
// 关键数据 - 必须成功
const [user, mainContent] = await Promise.all([
getUserData(),
getMainContent()
]);
// 次要数据 - 可有可无
const secondaryResults = await Promise.allSettled([
getRecommendations(),
getSidebarWidgets(),
getAdvertisement()
]);
return {
user,
mainContent,
secondaryData: processSecondaryResults(secondaryResults)
};
}
从 Promise.all 切换到 Promise.allSettled,虽然只是一个小小的改变,但却显著提升了应用的稳定性。用户不再因为某个非关键接口的失败而看到空白页面,而是能够继续使用其他正常的功能。
在实际开发中,理解不同工具的特点,并在合适的场景使用它们,这是提升代码质量的重要一步。如果你的项目中也存在类似的情况,不妨试试 Promise.allSettled,它可能会帮你避免很多意想不到的问题。
记住,好的代码不仅要考虑正常情况,还要为可能出现的异常情况做好准备。这样才能打造出真正稳定可靠的应用。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
Promise 想必大家十分熟悉,想想就那么几个 api,可是你真的了解 Promise 吗?本文根据 Promise 的一些知识点总结了十道题,看看你能做对几道。
本文写给有一定Promise使用经验的人,如果你还没有使用过Promise,这篇文章可能不适合你,Promise标准中仅指定了Promise对象的then方法的行为,其它一切我们常见的方法/函数都并没有指定.
Async/Await替代Promise的6个理由:Async/Await是近年来JavaScript添加的最革命性的的特性之一。它会让你发现Promise的语法有多糟糕,而且提供了一个直观的替代方法。
Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一,Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数
这篇文章是考虑如何自己实现一个简单 Promise,用以理解 Promise。和原生 Promise的调用方法一样,支持链式调用,本文实现的方法只能用于参考Promise的原理,还有很多特性没有实现,比如 race,all 方法的实现。
在对数组进行一些遍历操作时,发现有些遍历方法对Promise的反馈并不是我们想要的结果。async/await为Promise的语法糖,文中会直接使用async/await替换Promise;map可以说是对Promise最友好的一个函数了,
最近在使用axios库时遇到了个问题,后端接口报了500错误,但前端并未捕获到。在axios整体配置的代码中,过滤http code时,调用了filter401()、filter500(),但是这里注意并未将两个filter函数的结果返回,也就是并未返回promise,这就是导致问题出现的原因
想必接触过Node的人都知道,Node是以异步(Async)回调著称的,其异步性提高了程序的执行效率,但同时也减少了程序的可读性。如果我们有几个异步操作,并且后一个操作需要前一个操作返回的数据才能执行
你可以在 .then 里面 return 一个 Promise,每次执行 .then 的时候都会自动创建一个新的 Promise,对调用者来说,Promise 的 resolved/rejected 状态是唯一的,Promise 构造函数不是解决方案,使用 Promise.resolve
Promise的一些用法在此不多赘述,本篇主要带领你手写一个Promise源码,学完你就会发现:Promise没有你想象中的那么难.本篇大概分为以下步骤:实现简单的同步Promise、增加异步功能、增加链式调用then、增加catch finally方法、增加all race 等方法、实现一个promise的延迟对象defer、最终测试
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!