2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Quand le front-end doit-il contrôler les requêtes simultanées ? Lorsqu'il faut plusieurs fois pour demander les données requises. Par exemple, si l'interface renvoie une grande quantité de données à la fois, le navigateur sera bloqué dans le rendu ou même plantera. À ce moment-là, nous pouvons émettre 6 requêtes en même temps par lots, afin d'éviter un blocage ou un crash. .
Alors, comment le front-end contrôle-t-il les requêtes simultanées ?
Par exemple, s'il y a 20 demandes, vous devez suivre 3
Une fois que le premier groupe a terminé la demande, le deuxième groupe sera demandé, et ainsi de suite.
L'idée clé est de stocker la méthode de requête et les paramètres de requête dans un tableau, puis d'en demander 3 à la fois, puis de demander les 3 suivants une fois la requête terminée. Après le retour de chaque groupe de requêtes, les résultats sont enregistrés et une fois que toutes les requêtes sont renvoyées, tous les résultats sont renvoyés.
pControl
: Contrôleur de requêtes simultanées, transmettant le nombre maximum de simultanéités ;
add
: Ajouter une requête et des paramètres ;
start
: Démarrer la demande, renvoyer la promesse, réussir une fois la demande terminée.then
Obtenez tous les résultats ;
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
: Cette fonction renvoie un objet contenant add
etstart
Deux méthodes,add
Utilisé pour ajouter des tâches et des paramètres,start
Utilisé pour démarrer la requête, c'est une fermeture.
runAllTasks
: renvoie unpromise
, puis dansnew Promise
Exécuté en interne de manière récursiverunTask
, runTask réussitPromise.all
Exécuter des requêtes simultanées dansPromise.all().then()
appelle encore une foisrunTask
, implémentez un ensemble de requêtes à renvoyer, puis exécutez le deuxième ensemble de requêtes.
La clé pour réaliser l'attente de groupe est de
.then
appel récursif.
Réflexion : runAllTasks peut-il être implémenté à l'aide d'une boucle ?
Oui, il faut l'utiliser 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
}
Ne peut pas être utilisé dans une boucle for
.then
, sinon la boucle suivante n'attendra pas la boucle précédente.
utiliser for of
Implémentation itérative :
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
Pour les structures de boucle impératives, si vous souhaitez obtenir l'effet d'attente dans la boucle, vous devez utiliserasync
wrapper de fonction dans la boucleawait
,Hors service.then
。
forEach
、 map
、 filter
Les structures de boucle fonctionnelle telles que celles-ci ne prennent pas en charge les effets d'attente, car ces structures de boucle fonctionnelle sont synchrones et ne prennent pas en charge l'attente.
async
et循环
+await
Combiné pour obtenir l'effet d'attente entre les boucles.
promise.then
et递归
Combiné pour obtenir l'effet d'attente entre les boucles.
pControl
Définissez une valeur par défaut appropriée, définie sur6
, comme il s'agit du même nom de domaine, les requêtes simultanées du navigateur sont au nombre de 6.Ces deux améliorations sont simples. Voyons d'abord l'utilisation :
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)
})
À quoi sert le rappel de démarrage ?
Il est pratique pour les utilisateurs d'obtenir les résultats des demandes simultanées en cours et de calculer la progression.
p-control
version du paquet npmaccessible npm i p-control
Téléchargez et utilisez.
.then
Combiné avec la récursivité pour réaliser l'attente entre les tâches asynchrones ;for
、while
Attendez la boucle etasync
+ await
Utilisé en combinaison pour réaliser une attente entre des tâches asynchrones ;Promise.all
Implémentez plusieurs tâches asynchrones à exécuter simultanément.