Описание проблемы
Реализуйте функцию дозатора 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