Как реализовать аналог Promise.all() c очередью?
Как реализовать Promise.all() с динамической очередью фиксированной ёмкости,
то есть чтобы в отдельный момент времени в обработке находились, например, до 10 параллельных запросов?
const promises = Array(10)
.fill(null)
.map((item, i) => new Promise((resolve) => resolve(i)))
const arr = await PromiseAllByChanck.all(promises , 2)
Другими словами, чтобы запросы выполнялись сегментами массива запросов, поблочно?
Ответы (1 шт):
Дело в том, что каждый созданный Promise по сути и является запросом, отправленным на исполнение, поэтому в искомом решении не может быть такой сущности как массив "обещаний" promises.
То есть они все создаются и "отправляются на исполнение" прямо с этой строки:
const promises = Array(10)
.fill(null)
.map((item, i) => new Promise((resolve) => resolve(i)))
const five = await promises[5] // 5
Чтобы предотвратить это, можно "экранировать" их, точнее преобразовать в асинхронные функции:
const tasks = Array(10)
.fill(null)
.map((item, i) => async () => i)
const five = await tasks[5]() // 5
Тогда аналог Promise.all() со внутренней очередью будет выглядеть примерно так:
class ExecutorPool {
constructor(size) {
if (size < 1)
throw new Error('[ExecutorPool] Размер очереди меньше единицы.')
this._size = size
}
async execute(tasks) {
const results = Array(tasks.length)
const executors = Array(this._size)
.fill(null)
.map((e, executorId) => async (taskPool) => {
while (true) {
const task = taskPool.pop()
if (!task) break
const index = taskPool.length
results[index] = await task()
console.log(JSON.stringify({ taskId: results[index], executorId }))
}
})
const taskPool = [...tasks]
await Promise.all(executors.map((executor) => executor(taskPool)))
return results
}
}
new Promise(async () => {
const tasks = Array(10)
.fill(null)
.map((item, i) => async () => i)
const ePool = new ExecutorPool(2)
const results = await ePool.execute(tasks)
console.log(JSON.stringify(results))
})