0

0

深入理解Promise.allSettled的并发任务计时与性能分析

聖光之護

聖光之護

发布时间:2025-11-06 23:02:28

|

505人浏览过

|

来源于php中文网

原创

深入理解Promise.allSettled的并发任务计时与性能分析

本文旨在提供一种有效的方法,用于在使用`promise.allsettled`处理并发异步任务时,准确记录并分析每个任务的完成时间。通过自定义封装函数,我们可以将计时信息集成到`promise.allsettled`的返回结果中,从而帮助开发者识别性能瓶颈,优化任务分组策略,提升应用程序的响应效率。

异步任务并发处理与性能考量

在现代Web应用和Node.js服务中,处理多个异步操作(如API请求、数据库查询、文件读写)是常见需求。Promise.allSettled是一个强大的工具,它允许我们并发执行一组Promise,并在所有Promise都“落定”(无论成功或失败)后返回一个包含每个Promise状态和结果的数组。这对于需要等待所有任务完成才能进行下一步操作的场景非常有用,例如批量数据处理或多源数据聚合。

然而,Promise.allSettled的默认行为并不会提供每个单独Promise的执行时间。在进行性能优化时,了解每个并发任务的耗时至关重要。例如,如果您同时发起5个API调用,并发现其中某些调用显著慢于其他,那么将它们分组处理(例如,先处理快速的,再处理慢的)可能会提高用户体验或系统吞吐量。本文将介绍如何通过扩展Promise.allSettled的功能,来精确测量并获取每个并发任务的完成时间。

方案一:通过控制台日志记录任务耗时

最直接的方法是在每个Promise“落定”时记录其耗时。我们可以利用Promise.prototype.finally()方法,在每个Promise无论成功或失败时都执行一个回调函数,并在该回调中计算并打印从Promise.allSettled开始到当前Promise完成的时间差。

以下是一个实现此功能的辅助函数:

/**
 * 封装 Promise.allSettled,并在每个 Promise 完成时记录其耗时到控制台。
 * @param {Array>} promises - Promise 数组。
 * @returns {Promise[]>} - 与 Promise.allSettled 相同的返回结果。
 */
function allSettledTimedLog(promises) {
    const startTime = Date.now(); // 记录 Promise.allSettled 调用的起始时间

    // 遍历每个 Promise,使用 .finally() 拦截其完成事件
    const timedPromises = promises.map((p, index) => {
        return p.finally(() => {
            // 在 Promise 完成时计算耗时并打印
            console.log(`[任务 ${index}] 完成,耗时 ${Date.now() - startTime}ms`);
        });
    });

    // 将增强后的 Promise 数组传递给 Promise.allSettled
    return Promise.allSettled(timedPromises);
}

使用示例:

const task1 = new Promise(resolve => setTimeout(() => resolve('Task 1 Done'), 100));
const task2 = new Promise((resolve, reject) => setTimeout(() => reject('Task 2 Failed'), 500));
const task3 = new Promise(resolve => setTimeout(() => resolve('Task 3 Complete'), 200));

allSettledTimedLog([task1, task2, task3]).then(results => {
    console.log('所有任务落定结果:', results);
});
// 预期控制台输出类似:
// [任务 0] 完成,耗时 10Xms
// [任务 2] 完成,耗时 20Xms
// [任务 1] 完成,耗时 50Xms
// 所有任务落定结果: [...]

优点:

  • 实现简单直观。
  • 能够快速在开发过程中观察每个任务的耗时。

缺点:

开源电子商务系统(网店) iWebShop
开源电子商务系统(网店) iWebShop

iWebShop基于iWebSI框架开发,在获得iWebSI技术平台库支持的条件下,iWebShop可以轻松满足用户量级百万至千万级的大型电子商务网站的性能要求。站点的集群与分布式技术(分布式计算与存储/高可用性/负载均衡)被屏蔽在SI 平台之内,基于iWebShop并且按照SI平台库扩展规范开发的新增功能模块,也将同时获得这种超级计算与处理的能力。作为开源的LAMP电子商务系统,iWebShop

下载
  • 计时信息仅通过控制台输出,不易于程序化地获取和进一步处理。
  • 需要手动解析日志来获取性能数据。

方案二:将计时信息嵌入到 Promise.allSettled 结果中

为了更好地利用计时数据,我们可以将每个任务的耗时直接集成到Promise.allSettled的返回结果对象中。这意味着每个PromiseSettledResult对象(包含status和value/reason)将额外包含一个time属性,表示该任务的完成耗时。

以下是实现此功能的辅助函数:

/**
 * 封装 Promise.allSettled,并将每个 Promise 的耗时嵌入到返回结果中。
 * @param {Array>} promises - Promise 数组。
 * @returns {Promise & { time?: number }>>} - 包含耗时信息的 PromiseSettledResult 数组。
 */
function allSettledTimed(promises) {
    const startTime = Date.now();
    const taskTimes = new Array(promises.length); // 用于存储每个任务的耗时

    // 增强每个 Promise,使其在 finally 阶段记录耗时到 taskTimes 数组
    const enhancedPromises = promises.map((p, index) => {
        return p.finally(() => {
            taskTimes[index] = Date.now() - startTime; // 记录从开始到完成的耗时
        });
    });

    // 等待所有增强后的 Promise 落定
    return Promise.allSettled(enhancedPromises).then(results => {
        // 将记录的耗时信息合并到 Promise.allSettled 的结果中
        for (let i = 0; i < results.length; i++) {
            // 为每个结果对象添加 'time' 属性
            results[i].time = taskTimes[i];
        }
        return results;
    });
}

使用示例:

const apiCall1 = new Promise(resolve => setTimeout(() => resolve({ data: 'User Info' }), 300));
const apiCall2 = new Promise((resolve, reject) => setTimeout(() => reject(new Error('Auth Failed')), 600));
const apiCall3 = new Promise(resolve => setTimeout(() => resolve({ data: 'Product List' }), 150));

allSettledTimed([apiCall1, apiCall2, apiCall3]).then(results => {
    console.log('所有任务及耗时结果:', results);
    // 遍历结果,分析耗时
    results.forEach((res, index) => {
        if (res.status === 'fulfilled') {
            console.log(`任务 ${index} 成功,耗时 ${res.time}ms,结果:`, res.value);
        } else {
            console.log(`任务 ${index} 失败,耗时 ${res.time}ms,原因:`, res.reason);
        }
    });
});
// 预期控制台输出类似:
// 所有任务及耗时结果: [
//   { status: 'fulfilled', value: { data: 'User Info' }, time: 30X },
//   { status: 'rejected', reason: [Error: Auth Failed], time: 60X },
//   { status: 'fulfilled', value: { data: 'Product List' }, time: 15X }
// ]
// 任务 0 成功,耗时 30Xms,结果: { data: 'User Info' }
// 任务 1 失败,耗时 60Xms,原因: Error: Auth Failed
// 任务 2 成功,耗时 15Xms,结果: { data: 'Product List' }

优点:

  • 计时信息直接集成到返回结果中,便于程序化访问和后续处理(如数据分析、生成报告)。
  • 结果结构清晰,一个对象包含所有相关信息。

缺点:

  • 相对于方案一,实现略微复杂,需要一个额外的数组来临时存储计时信息。

注意事项与应用场景

  1. 输入类型限制: 上述两种实现都假定传入的promises参数是一个数组,以便使用.map()方法。如果需要支持任意可迭代对象(如Set、Map),则需要进行额外的类型转换或迭代处理。
  2. 计时基准: 记录的耗时是从allSettledTimed函数被调用时开始计算的。这意味着如果您的Promises在调用allSettledTimed之前就已经启动,那么记录的耗时将是它们从allSettledTimed调用点到完成的时间,而不是它们实际的整个生命周期。对于大多数并发API调用场景,通常会在同一时间点发起所有请求并立即调用allSettledTimed,因此这种计时方式是准确且有意义的。
  3. 性能分析: 获得单个任务的耗时数据后,您可以:
    • 识别慢速任务: 找出那些显著耗时更长的任务,它们可能是性能瓶颈。
    • 优化分组策略: 根据任务耗时,考虑是否将快速任务和慢速任务分开处理,以减少整体等待时间。例如,先显示快速任务的结果,再异步加载慢速任务。
    • 资源分配: 评估并发任务对系统资源(如CPU、内存、网络带宽)的影响。
    • 服务质量监控: 持续监控关键异步操作的耗时,及时发现服务降级。

总结

通过对Promise.allSettled进行简单的封装和增强,我们可以轻松地获取到每个并发任务的独立完成时间。无论是通过控制台日志进行快速调试,还是将计时数据嵌入到结果中进行更深入的程序化分析,这些技术都为开发者提供了宝贵的性能洞察力。在构建高性能、响应迅速的应用程序时,理解并优化异步任务的执行效率是不可或缺的一环,而精确的计时数据正是实现这一目标的关键。

相关专题

更多
golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

75

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

36

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

60

2025.11.17

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

40

2025.11.27

C++类型转换方式
C++类型转换方式

本专题整合了C++类型转换相关内容,想了解更多相关内容,请阅读专题下面的文章。

299

2025.07.15

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

510

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

244

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

258

2023.08.03

AO3中文版入口地址大全
AO3中文版入口地址大全

本专题整合了AO3中文版入口地址大全,阅读专题下面的的文章了解更多详细内容。

1

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.4万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号