Описание проблемы
Реализуйте функцию дозатора JavaScript, она должна возвращать объект двумя методами: «добавить» и «удалить».
«добавить» должен добавить задачу в очередь и запустить задачи в очереди пакетами указанного размера.
«удалить» должно удалить задачу из очереди
Дозатор проверяет, есть ли запущенные задачи, если нет, то запускает задачи в очереди до тех пор, пока очередь не опустеет.
Задача определяется как функция, которая возвращает обещание.
Выполнение
Вы можете проверить этот репозиторий github: jinxuan/js-batcher (github.com)
Структура данных
Для начала нам нужно определить основную структуру данных.
Нам нужна карта задач, где ключ — это уникальное целое число, значение идентификатора — это задача.
Нам также нужен связанный список/очередь
function batcher(batchSize = 10) { let taskMap = {}; let runnningTasks = {] let running = false; let nextId = 0; let head = {id: null, next: null}; let tail = head; }
Удалить API
remove(id) { if (!taskMap[id]) return; const node = taskMap[id]; if (!runningTasks[id]) node.reject('Batcher task aborted'); delete taskMap[id]; Object.assign(node, node.next); if (node.id) taskMap[node.id] = node; else tail = node; },
Добавить API
add(task) { const id = nextId(); console.log('batcher add task', id); const promise = new Promise((resolve, reject) => taskMap[id] = Object.assign(tail, { id, task, resolve, reject })); taskMap[id].next = tail = newTail(); if (!running) { (async() => { running = true; while (head.next) { while (Object.values(runningTasks).length >= batchSize) await Promise.race(Object.values(runningTasks)); const { id, task, resolve, reject } = head; runningTasks[id] = (async() => { try { resolve(await task()); } catch (e) { reject(e); } finally { delete runningTasks[id]; } })(); console.log('Finish running task ', id); this.remove(id); } running = false; })(); } return { id, promise }; } };
Улучшение
Добавьте другой API для отмены запроса
Ссылка:
javascript — Понимание использования promise.race () — Stack Overflow