Сериализовать async-записи так, чтобы две не шли одновременно
Реализуйте writeFileQueued(write), возвращающую функцию enqueue(data). Нижележащая write(data) возвращает промис и не должна никогда выполняться одновременно — каждый вызов должен ждать завершения предыдущего перед стартом. Требования: вызовы выполняются в порядке постановки в очередь; enqueue возвращает промис, завершающийся результатом или ошибкой именно этой записи; сбой одной записи не должен ломать очередь для последующих.
function writeFileQueued(write) {
// вернуть enqueue(data)
// ваш код здесь
}
Допишите реализацию.
Держите промис tail для конца очереди, начиная с Promise.resolve(). В enqueue(data) цепляйте запись: const run = tail.then(() => write(data)). Продвигайте tail = run.catch(() => {}), чтобы одно отклонение не отравило последующие записи, и возвращайте run вызывающему.
- ✗Продвигать tail без
catch, из-за чего одно отклонение ломает всю очередь - ✗Возвращать общий tail, так что каждый вызывающий видит результат чужой записи
- ✗Запускать записи одновременно вместо цепляния каждой на предыдущую
- →Почему tail должен проглатывать ошибки, а возвращаемый промис — сохранять их?
- →Как добавить лимит длины очереди, отклоняющий новые постановки?
Решение
Единый «хвост» очереди; каждая запись цепляется на предыдущую.
function writeFileQueued(write) {
let tail = Promise.resolve(); // конец очереди
return function enqueue(data) {
const run = tail.then(() => write(data)); // ждём предыдущую, потом пишем
tail = run.catch(() => {}); // хвост глотает ошибки → очередь жива
return run; // вызывающий видит свой результат/ошибку
};
}
Как это работает
tail всегда указывает на завершение последней поставленной записи. Новая запись стартует только в tail.then(...), поэтому write не запускается, пока предыдущий не завершится — конкуренции нет, порядок сохранён. tail продвигается версией с .catch(() => {}), чтобы отклонение не отравило цепочку для будущих записей. Вызывающему возвращается run (без catch), поэтому он получает именно свой результат или ошибку.