赞
踩
什么情况需要前端控制并发请求,在需要多次才能请求完所需数据的时候。比如接口一次返回,数据很多,让浏览器渲染卡顿甚至崩溃,这时候我们可以分批同时发出6个请求,这样就可以避免卡顿或者崩溃。
那么前端如何控制并发请求呢?
比如有 20 个请求,需要按照 3
个一组,第一组请求完毕后再请求第二组,以此类推。
关键思路,把请求方法和请求参数使用一个数组存起来,然后每次请求3个,请求完毕后再请求下一个3个。每组请求返回后,把结果保存起来,等所有请求都返回后,再把所有结果返回。
pControl
: 并发请求控制器, 传递最大并发数;add
: 添加请求和参数;start
: 开始请求,返回promise, 请求完毕后通过 .then
获取所有结果;
function pControl(limit) { const taskQueue = [] // {task: Function, params: any[]}[] return { add, start } function add(task, params) { taskQueue.push({ task, params }) } function start() { return runAllTasks() } function runAllTasks() { const allResults = [] return new Promise((resolve) => { runTask() function runTask() { if (taskQueue.length === 0) { // 递归结束 return resolve(allResults) } const needRunSize = Math.min(taskQueue.length, limit) const tasks = taskQueue.splice(0, needRunSize) const promises = tasks.map(({ task, params }) => task(params)) Promise.all(promises).then((resList) => { allResults.push(...resList) // NOTE 递归调用的位置很关键 runTask() }) } }) } }
pControl
: 这个函数返回一个对象,包含 add
和 start
两个方法,add
用来添加任务和参数,start
用来开始请求,是一个闭包。runAllTasks
: 返回一个promise
,然后在new Promise
内部递归地执行runTask
, runTask 通过Promise.all
执行并发请求,在Promise.all().then()
再次调用runTask
,实现一组请求返回,再执行第二组请求。实现分组等待的关键是在
.then
中递归调用。思考: runAllTasks 可以使用循环实现吗?
能,需要使用 async 和 for 循环 + await
:
async function runAllTasks2() { const allResults = [] const groupArr = [] let startIndex = 0 // 划分分组 while (startIndex < taskQueue.length) { const arr = taskQueue.slice(startIndex, startIndex + limit) groupArr.push(arr) startIndex += limit } for (let index = 0; index < groupArr.length; index++) { const pList = groupArr[index].map(({ task, params }) => task(params)) const res = await Promise.all(pList) allResults.push(...res) } return allResults }
在 for 中循环中不能使用
.then
,否则下一次循环不会等待上一次循环。
使用 for of
迭代实现:
async function runAllTasks2() { const allResults = [] const groupArr = [] let startIndex = 0 // 划分分组 while (startIndex < taskQueue.length) { const arr = taskQueue.slice(startIndex, startIndex + limit) groupArr.push(arr) startIndex += limit } // 迭代分组 const it = groupArr.entries() for (const [key, value] of it) { const pList = value.map(({ task, params }) => task(params)) const res = await Promise.all(pList) allResults.push(...res) } return allResults }
for
、 while
、 for...of
等命令式循环结构,想要在循环中实现等待效果,必须使用 async
函数包裹循环中的 await
,不能使用 .then
。
forEach
、 map
、 filter
等函数式循环结构,不支持等待效果,因为这些函数式循环结构是同步的,不支持等待。
async
和循环
+await
结合,实现循环之间等待效果。
promise.then
和递归
结合,实现循环之间等待效果。
pControl
设置一个合适的默认值,设置为6
,因为同一个域名在,浏览器的并发请求是 6 个。这两个改进很简单。先看用法:
const asyncTaskControl = pControl() // 默认 6 asyncTaskControl.add(task, params1) asyncTaskControl.add(task, params2) // ... asyncTaskControl.add(task, params10) asyncTaskControl.start((res, doneSize) => { // 获取每组请求的结果 和当前完成了多少请求 console.log(res) // [{index:number,result:data}] console.log(doneSize) }).then(allResults => { // 所有请求结果 console.log(allResults) })
start 回调有什么作用呢?
方便使用者拿当前并发请求的结果,方便计算完成进度。
p-control
npm 包发布可通过 npm i p-control
下载使用。
.then
和递归结合,实现异步任务之间等待;for
、while
等循环和async
+ await
结合使用,实现异步任务之间等待;Promise.all
实现多个异步任务并发执行。作为开发者,我们需要保持好奇心和学习热情,不断探索新的技术,只有这样,我们才能在这个快速发展的时代中立于不败之地。介绍一款程序员都应该知道的软件JNPF快速开发平台,很多人都尝试用过它,它是功能的集大成者,任何信息化系统都可以基于它开发出来。
JNPF可以实现应用从创建、配置、开发、测试到发布、运维、升级等完整生命周期的管理。减少了传统应用程序的代码编写量,通过图形化、可视化的界面,以拖放组件的方式,即可快速生成应用程序的产品,大幅降低了开发企业管理类软件的难度。
当然,我更建议大家成为一个全栈,不要把自己的定位局限于前端。
感谢阅读本文
如果有什么建议,请在评论中让我知道。我很乐意改进。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。