Почему нельзя использовать Promise.all для решения задачи с покупателями в JavaScript
Что проверяют
Понимаете ли вы, что Promise.all это не «запустить параллельно», а лишь ожидание уже запущенных промисов, и видите ли задачи, где параллельный запуск ломает саму логику.
Как отвечать
Разберите три свойства, из-за которых он тут не подходит.
Первое: промис стартует в момент создания. К моменту вызова Promise.all все запросы уже ушли, поэтому ограничить нагрузку или выстроить операции в очередь он не поможет. Чтобы управлять запуском, в массиве должны лежать функции, возвращающие промис, а не сами промисы.
Второе: первое же отклонение завершает общий промис, но остальные не отменяются. Они продолжают работать, результаты уходят в никуда, а побочные эффекты остаются: списание уже произошло, письмо уже ушло.
Третье, главное: задача про покупателей последовательна по смыслу. Все параллельные ветки читают один и тот же остаток товара, каждая видит, что товара хватает, и каждая его резервирует. Итог: продано больше, чем есть. Это гонка, и её не лечит ни allSettled, ни повтор.
for (const buyer of buyers) {
await serve(buyer); // остаток честно обновляется между шагами
}Что предложить: последовательный цикл, когда шаги зависят друг от друга; пул с ограничением параллелизма, когда они независимы, но заваливать бэкенд нельзя; Promise.allSettled, когда нужны все результаты вместе с ошибками. И назовите правильное место для проверки остатка: транзакция или атомарное обновление на стороне хранилища.
Где спотыкаются
Считают, что Promise.all отменяет остальные промисы после ошибки. Отмены в промисах нет вообще, для прерывания нужен AbortController, который вы прокидываете в каждый запрос сами.
Второе: меняют Promise.all на allSettled и считают, что починили. Порядок выполнения и гонку это не меняет, меняется лишь то, что ошибки перестают всплывать и молча теряются.
Третье: путают асинхронность с многопоточностью. Код исполняется в одном потоке, гонка возникает не из-за параллельных инструкций, а из-за того, что между чтением остатка и его записью управление уходит в другую ветку.