2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
When does the front-end need to control concurrent requests? When multiple requests are needed to complete the required data. For example, if the interface returns a lot of data at once, the browser rendering will be stuck or even crash. At this time, we can send 6 requests in batches at the same time to avoid stuck or crash.
So how does the front end control concurrent requests?
For example, if there are 20 requests, you need to follow 3
After the first group of requests is completed, the second group is requested, and so on.
The key idea is to store the request method and request parameters in an array, and then request 3 at a time. After the request is completed, request the next 3. After each group of requests returns, save the results, and return all the results after all requests are returned.
pControl
: Concurrent request controller, passing the maximum number of concurrent requests;
add
: Add request and parameters;
start
: Start the request, return promise, and pass after the request is completed.then
Get all results;
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
: This function returns an object containing add
andstart
Two methods,add
Used to add tasks and parameters,start
Used to start the request, which is a closure.
runAllTasks
: Return apromise
, thennew Promise
Execute recursively insiderunTask
, runTask byPromise.all
Execute concurrent requests,Promise.all().then()
Call againrunTask
, implement the return of one set of requests, and then execute the second set of requests.
The key to implementing group waiting is
.then
Recursive call in .
Thinking: Can runAllTasks be implemented using a loop?
Yes, need to use 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
}
It cannot be used in a for loop.
.then
, otherwise the next loop will not wait for the previous loop.
use for of
Iterative implementation:
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
If you want to achieve the waiting effect in the loop, you must useasync
Function wrapping loopawait
,Out of service.then
。
forEach
、 map
、 filter
Functional loop structures such as , do not support waiting effects, because these functional loop structures are synchronous and do not support waiting.
async
and循环
+await
Combined to achieve the waiting effect between loops.
promise.then
and递归
Combined to achieve the waiting effect between loops.
pControl
Set a suitable default value to6
, because the same domain name is in, the browser's concurrent requests are 6.These two improvements are very simple. Let's look at the usage first:
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)
})
What is the function of the start callback?
It is convenient for users to get the results of current concurrent requests and calculate the completion progress.
p-control
npm package publishingaccessible npm i p-control
Download and use.
.then
Combined with recursion, it can realize waiting between asynchronous tasks;for
、while
Equicyclic andasync
+ await
Used in combination to implement waiting between asynchronous tasks;Promise.all
Implement concurrent execution of multiple asynchronous tasks.