моя контактная информация
Почтамезофия@protonmail.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Когда интерфейсу необходимо контролировать одновременные запросы? Когда требуется несколько раз для запроса необходимых данных? Например, если интерфейс возвращает много данных одновременно, браузер зависнет при рендеринге или даже выйдет из строя. В это время мы можем отправлять 6 запросов одновременно пакетами, чтобы избежать зависания или сбоя.
Так как же интерфейс контролирует одновременные запросы?
Например, если запросов 20, нужно следовать 3
После того как первая группа выполнит запрос, будет запрошена вторая группа и так далее.
Основная идея состоит в том, чтобы сохранить метод запроса и параметры запроса в массиве, затем запрашивать по 3 за раз, а затем запрашивать следующие 3 после завершения запроса. После возврата каждой группы запросов результаты сохраняются, а после возврата всех запросов возвращаются все результаты.
pControl
: Контроллер одновременных запросов, передающий максимальное количество параллелизма;
add
: Добавить запрос и параметры;
start
: Запустить запрос, вернуть обещание, пройти после завершения запроса..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)
})
Что делает обратный вызов?
Пользователям удобно получать результаты текущих одновременных запросов и рассчитывать ход выполнения.
p-control
выпуск пакета npmдоступный npm i p-control
Скачайте и пользуйтесь.
.then
В сочетании с рекурсией для обеспечения ожидания между асинхронными задачами;for
、while
Подождите цикла иasync
+ await
Используется в сочетании для достижения ожидания между асинхронными задачами;Promise.all
Реализуйте несколько асинхронных задач для одновременного выполнения.