前端基于 axios 实现批量任务调度管理器 demo

一、背景介绍

这是一个基于 axios 实现的批量任务调度管理器的 demo。它使用了axios、promise 等多种技术和原理来实现批量处理多个异步请求,并确保所有请求都能正确处理并报告其状态。

假设有一个场景:有一个任务列表,有单个任务的处理功能,但是用户提出需要增加批量处理任务的需求,那么如果 20 个任务,30 个任务,我们显然可以集成在一次请求里,无非就是服务器处理的压力变大,时间慢一点,但是如果越来越多的任务,用户要等待很久,后端为支持这些,只能改成异步处理,等待时间就很不可控了。并且在这个过程中,很有可能对正在排队的任务进行其他处理,会发生一些不必要的“错误”。所以提出前端对这些任务“批量处理”,并且对这些任务处理时可以先对任务进行过滤和去重等,统计并发请求的状态并展示,最后实现了一个简单的【批量任务调度管理器 demo】。

这个功能还略显青涩,所以后续又进行了优化和完善,最近有新的想法,借助第三方库,比如使用类似p-limit或 p-queue 的任务队列库来管理批量任务。这些库提供了更高级的功能,如任务调度、重试、延迟执行等,这些待实验。

二、功能介绍

这个 demo 实现了以下功能:

  1. 批量处理:用户可以一次性提交多个任务,这些任务会被批量处理,将请求任务分成固定大小(groupSize)的批次进行处理,以避免同时发送过多请求导致服务器压力过大或浏览器资源耗尽。
  2. 并发控制:通过递归调用 requestFunction 和控制 groupSize,实现了对并发请求数量的控制。在每次请求完成后再启动新的请求,确保同时运行的请求数量保持在合理范围内。(有优化
  3. 过滤和去重:使用 filter 和 findIndex 方法,对 tableData 进行过滤和去重,确保每个任务只被处理一次,也可以自定义其他处理方式。
  4. 状态管理:计数(successCount 和 errorCount)处理结果,使用 ElMessage 和 ElNotification 进行用户提示,反馈批量操作的结果。
  5. 异步操作和错误处理:通过 axios 库发送异步 HTTP 请求,使用 then, catch 和 finally 方法处理请求结果和错误,并在出错时记录错误信息。(有优化

三、功能代码

// 批量处理多个任务
const batchOperation = (title, operationType, axiosConfig, shouldFilterList) => {startLoading() // 可忽略,自定义的加载动画const groupSize = 5 // 分组,每组五个请求let successCount = 0 // 成功的请求let errorCount = 0 // 失败的请求let errorMessages = [] // 请求失败时的错误信息记录// 过滤得到需要发生请求的任务列表const requestTaskList = shouldFilterList? tableData.value.filter((item, index, arr) => arr.findIndex((val) => val.id == item.id) == index): tableData.valueif (requestTaskList.length == 0) {ElMessage.error('没有可操作的任务!')stopLoading()return}// 处理请求后的成功或者失败const handleResponse = (error) => {if (error) {errorCount++errorMessages.push(error)} else {successCount++}if (successCount + errorCount === requestTaskList.length) {stopLoading()const message =errorCount === 0? `${requestTaskList.length} 个任务,全部处理成功。`: `${requestTaskList.length} 个任务,${successCount} 个处理成功,${errorCount} 个处理失败。`ElNotification({title: `${title}结果`,message,type: errorCount === 0 ? 'success' : 'warning'})if (errorCount > 0) {console.error('处理失败的任务:', errorMessages)}}}//发送请求--借助递归const requestFunction = () => {// isUnmount是控制是否卸载当前组件if (isUnmount.value || nowIndex >= requestTaskList.length) {return}const row = requestTaskList[nowIndex++]const params = { ...row } // 自定义传参axios.request({ url: axiosConfig.url, method: axiosConfig.method, params }).then((res) => {if (res.data.code == 200) {handleResponse(null)} else {handleResponse(res.data.message)}}).catch(handleResponse).finally(requestFunction)}let nowIndex = 0for (let i = 0; i < groupSize; i++) {requestFunction()}
}// 批量处理
const batchAll = () => {batchOperation('标题','batch', //处理参数的标识{url: '/batch-task',method: 'get',params: { task_id: '', id: '' }},true // 是否过滤列表)
}// 可忽略
const startLoading = () => {// 显示加载动画或状态containerLoading.value = true
}const stopLoading = () => {// 隐藏加载动画或状态containerLoading.value = false
}// 因为是vue,所以在组件卸载之前,取消所有未完成的请求----可忽略
onBeforeUnmount(() => {isUnmount.value = true
})

以上功能能实现的是上述阐述的功能,也算一个简单的批量任务调度管理器,但是还有很多优化方向:

  1. 错误信息收集和展示:
    当前的错误处理仅记录了错误计数。可以改进为记录详细的错误信息,并在批量操作完成后展示这些错误信息,帮助用户理解哪些任务失败了以及原因(这个看需求)。
  2. 动态并发控制:
    使用动态并发控制,根据当前系统负载或网络状况调整并发请求数量,进一步优化性能和稳定性(这个需要依靠工具库完成)。
  3. 任务重试机制:
    为失败的请求添加重试机制,例如在某个请求失败后,可以重试一定次数,以提高成功率(这个看需求)。
  4. Promise.all 优化:
    使用 Promise.all 处理每一批次的请求,而不是递归调用 requestFunction,可以使代码更简洁,并减少递归带来的栈深度问题(这个现在就可以优化)。

四、功能优化

现在做的是基于 promise.all 的优化。我们要知道,promise 本来就是 JS 有的一个 API,那么当时我为何不考虑它呢,还是我当时没有考虑到。
Axios 是基于 Ajax 和 Promise 封装,本来就可以利用 Promise 来更好的管控请求回调嵌套造成的回调地狱,如果不加控制,查了一下,那种递归确实可能会造成调用栈过深,出现栈溢出问题(我还没有遇到过,不知道这种情况是什么样的)。

优化前后比较

通过递归调用 requestFunction 来处理任务,这种方式虽然有效,但有以下几个缺点:

1. 递归深度问题:对于大量任务,递归调用可能导致调用栈过深,出现栈溢出问题。
2. 复杂性和可维护性:递归调用使代码较为复杂,逻辑不直观,不容易维护。
3. 难以控制并发:递归调用在控制并发请求数量上不够灵活。

优化后的方式使用了 Promise.all,通过批量处理的方式来提高代码的可读性和可靠性:

1. 避免递归:使用 Promise.all 处理每个批次的请求,避免了递归调用导致的栈深度问题。
2. 简化代码:优化后的代码结构更加清晰,逻辑更加直观,便于维护。
3. 控制并发:批量处理的方式更加灵活,可以方便地控制并发请求的数量。
4. 更好的错误处理:单独处理每个请求的错误,不会因为一个请求失败而导致整个批次停止

优化代码

// 批量处理
const batchOperation = (title, operationType, axiosConfig, shouldFilterList, tabs) => {startLoading()const groupSize = 5let successCount = 0let errorCount = 0let errorMessages = []const requestTaskList = shouldFilterList? tableData.value.filter((item, index, arr) => arr.findIndex((val) => val.id == item.id) == index): tableData.valueif (requestTaskList.length === 0) {ElMessage.error('没有可操作的任务!')stopLoading(tabs)return}const handleResponse = () => {if (successCount + errorCount === requestTaskList.length) {stopLoading(tabs)const message =errorCount === 0? `${requestTaskList.length} 个任务,全部处理成功。`: `${requestTaskList.length} 个任务,${successCount} 个处理成功,${errorCount} 个处理失败。`ElNotification({title: `${title}结果`,message,type: errorCount === 0 ? 'success' : 'warning'})if (errorCount > 0) {console.error('处理失败的任务:', errorMessages)}}}const makeRequest = (row) => {let params = {}return axios.request({ url: axiosConfig.url, method: axiosConfig.method, params }).then((res) => {if (res.data.code === 200) {successCount++} else {errorCount++errorMessages.push(res.data.message)}}).catch((error) => {errorCount++errorMessages.push(error.message || error)})}const executeBatch = (batch) => {return Promise.all(batch.map(makeRequest)).catch(() => {}) // 忽略批次中的错误,单独处理}let nowIndex = 0const batches = []while (nowIndex < requestTaskList.length) {const batch = requestTaskList.slice(nowIndex, nowIndex + groupSize)batches.push(executeBatch(batch))nowIndex += groupSize}Promise.all(batches).finally(handleResponse)
}

五、总结

两者其实都是并发处理一组又一组的请求,从性能上,我选择 20 个任务,实现的效果,优化后和优化前:
在这里插入图片描述

可以看得出,其实两者没有什么区别,可能因为我的实验数量太少,但是我查阅了资料,得出使用 Promise.all 的优点:

代码简洁:Promise.all 的实现方式较为简单,代码可读性强。
无栈深度问题:Promise.all 没有递归调用的问题,不会导致栈溢出。
就以上两点,也算是有了一点点效果吧。

最后,想试试另一种工具库来实现这个功能,就是借助上面提到的库,未完~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/51607.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Qt】QLCDNumberQProgressBarQCalendarWidget

目录 QLCDNumber 倒计时小程序 相关属性 QProgressBar 进度条小程序 相关设置 QLCDNumber QLCDNumber是Qt框架中用于显示数字或计数值的小部件。通常用于显示整数值&#xff0c;例如时钟、计时器、计数器等 常用属性 属性说明intValueQLCDNumber显示的初始值(int类型)va…

企业版邮箱适用哪些企业

企业邮箱适合哪些企业呢&#xff1f;企业版邮箱为企业提供安全、稳定、集成的邮件服务&#xff0c;支持初创、中小、大型企业及特定行业需求。ZohoMail作为优质提供商&#xff0c;提供多层安全措施、移动访问、集成能力及定制化服务&#xff0c;满足不同规模企业需求。 一、企…

2023年系统架构设计师考试总结

原文链接&#xff1a;https://www.cnblogs.com/zhaotianff/p/17812187.html 上周六参加了2023年系统架构设计师考试&#xff0c;这次考试与以前有点区别&#xff0c;是第一次采用电子化考试&#xff0c;也是教材改版后的第一次考试。 说说考前准备&#xff1a;为了准备这次考试…

基于微信小程序的校园警务系统/校园安全管理系统/校园出入管理系统

摘要 伴随着社会以及科学技术的发展&#xff0c;小程序已经渗透在人们的身边&#xff0c;小程序慢慢的变成了人们的生活必不可少的一部分&#xff0c;紧接着网络飞速的发展&#xff0c;小程序这一名词已不陌生&#xff0c;越来越多的学校机构等都会定制一款属于自己个性化的小程…

《通讯世界》是什么级别的期刊?是正规期刊吗?能评职称吗?

问题解答 问&#xff1a;《通讯世界》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的第一批认定学术期刊。 问&#xff1a;《通讯世界》级别&#xff1f; 答&#xff1a;国家级。主管单位&#xff1a;科学技术部 主办单位&#xff1a;中国科学技…

关于虚拟机在桥接模式下连接网络问题的记录

2024年7月28日03:49:19 环境&#xff1a;ubuntu22.04 desktop 虚拟机 问题&#xff1a;使用wget下载nginx安装包时出现问题&#xff0c;443端口持续无连接成功回复。 随后在确定配置ip无问题&#xff0c;检查了其正常访问互联网&#xff0c;随后试图ping niginx网站&#xff…

基于OSS前端直传的分片上传以及断点续传

一、大文件分片上传 原型 大文件如果直接上传的话由于nginx的限制会导致响应500报错&#xff0c;或者响应时间过长导致响应超时 并且大文件上传有如下缺点 上传时间长: 对于大文件&#xff0c;直接上传可能需要较长时间&#xff0c;特别是在网络速度较慢或不稳定的情况下。这…

ChatGPT秘籍:如何用AI阅读文献,提升你的学术效率

在当今信息泛滥的时代&#xff0c;迅速高效地搜集与处理信息显得尤为关键。本文将聚焦于如何利用ChatGPT高效阅读文献与文档&#xff0c;并提供详尽的技巧、心得以及实用的指令和插件解析&#xff0c;助你充分发挥ChatGPT的潜能。无论你是学生、科研人员还是行业从业者&#xf…

雪花算法的一些问题解析

前言 最近做项目&#xff0c;有些老旧项目&#xff0c;需要生成分布式唯一ID&#xff0c;不允许重复&#xff0c;此时如果要对其他中间件和数据库依赖小&#xff0c;那么就需要一套固定的ID生成规则&#xff0c;雪花算法就正当合适&#xff0c;当时Twitter就是用来存储数据库I…

JSP基础语法与指令

任何语言都有自己的语法&#xff0c;在java中有&#xff0c;JSP作为java技术的一种应用&#xff0c;它拥有一些自己扩充的语法(了解知道即可&#xff01;&#xff01;&#xff01;)&#xff0c; Java所有语法都支持&#xff01; JSP表达式 <html><head><title…

【Redis 初阶】初识 Redis

一、了解 Redis Redis 官网&#xff1a;Redis - The Real-time Data Platform Redis 是一种基于键值对&#xff08;key-value&#xff09;的 NoSQL 数据库。与很多键值对数据库不同的是&#xff0c;Redis 中的 key 都是 string&#xff08;字符串&#xff09;&#xff0c;值&a…

计算机毕业设计LSTM+Tensorflow股票分析预测 基金分析预测 股票爬虫 大数据毕业设计 深度学习 机器学习 数据可视化 人工智能

|-- 项目 |-- db.sqlite3 数据库相关 重要 想看数据&#xff0c;可以用navicat打开 |-- requirements.txt 项目依赖库&#xff0c;可以理解为部分技术栈之类的 |-- data 原始数据文件 |-- data 每个股票的模型保存位置 |-- app 主要代码文件夹 | |-- mod…

汽车辐射大?技术来救它:整车辐射抗扰发射天线仿真建模及性能预测

摘要 针对车辆电磁辐射抗扰度测试条件要求高、预测难度大的问题&#xff0c;通过仿真软件建立电磁抗扰度测试发射天线&#xff08;简称抗扰发射天线&#xff09;模型及无车情况下的电磁抗扰试验场强环境&#xff0c;为整车电磁辐射抗扰性能的预测搭建了一个仿真平台。 验证试验…

纹理映射学习笔记

概述 本文的纹理映射将三维曲面与二维的纹理建立对应关系。 曲面参数表达&#xff1a; x x ( s , t ) , y y ( s , t ) , z z ( s , t ) x x(s,t), y y(s,t), zz(s,t) xx(s,t),yy(s,t),zz(s,t) 即给定纹理坐标(s,t),我们能可以计算出曲面坐标(x,y,z) 映射 考虑由参数…

渲染技术如何帮助设计内容实现从平面到立体的转换

随着数字艺术和视觉特效的飞速发展&#xff0c;三维建模与渲染技术在影视、游戏、广告、工业设计、建筑可视化等多个领域展现出了其不可或缺的重要性。这一技术不仅实现了从平面到立体的跨越&#xff0c;还极大地丰富了视觉表达的层次感和真实感。 三维建模&#xff1a;构建虚…

ZYNQ 自定义IP端口映射

在做自定义IP时&#xff0c;对于总线接口&#xff0c;我们可以将其信号封装成接口&#xff0c;避免信号一个个地连接。在本实验中&#xff0c;需要封装axis slave接口&#xff0c;在Ports and Interfaces界面中&#xff0c;选择需要封装的信号&#xff0c;右键选择Add Bus Inte…

分享高效数据恢复工具:转转大师数据恢复软件等三款工具

哎&#xff0c;说起来都是泪啊&#xff0c;前阵子我那台陪伴了我无数个日夜的电脑&#xff0c;突然间就像跟我玩起了“躲猫猫”&#xff0c;一不留神&#xff0c;几个重要文件夹就这么悄无声息地“蒸发”了。心里那个急啊&#xff0c;就像热锅上的蚂蚁&#xff0c;团团转。好在…

Linux系统之部署记忆配对网页小游戏

Linux系统之部署记忆配对网页小游戏 一、小游戏介绍1.1 小游戏简介1.2 项目预览二、本次实践介绍2.1 本地环境规划2.2 本次实践介绍三、检查本地环境3.1 检查系统版本3.2 检查系统内核版本3.3 检查软件源四、安装Apache24.1 安装Apache2软件4.2 启动apache2服务4.3 查看apache2…

【中项第三版】系统集成项目管理工程师 | 第 11 章 规划过程组⑥ | 11.15 - 11.17

前言 第11章对应的内容选择题和案例分析都会进行考查&#xff0c;这一章节属于10大管理的内容&#xff0c;学习要以教材为准。本章上午题分值预计在15分。 目录 11.15 规划资源管理 11.15.1 主要输入 11.15.2 主要工具与技术 11.15.3 主要输出 11.16 估算活动资源 11.1…