Работа с наблюдаемыми позволяет упростить эту задачу (вместо использования императивного программирования).
Браузер обычно позволяет вам сделать 6 запросов параллельно и поставит в очередь другие. Но мы не хотим, чтобы браузер управлял этой очередью для нас (или если мы работаем в среде узлов, у нас не будет такой для бывших).
Что мы хотим: мы хотим загрузить много файлов. Их следует ставить в очередь и загружать как можно более эффективно, выполняя 5 запросов параллельно. (поэтому мы оставляем 1 бесплатной для других запросов в нашем приложении).
Чтобы продемонстрировать это, давайте сначала создадим несколько макетов:
function randomInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
const mockPayrollsService = {
sendFilesPaymentName: (file: File) => {
return of(file).pipe(
// simulate a 500ms to 1.5s network latency from the server
delay(randomInteger(500, 1500))
);
}
};
// array containing 50 files which are mocked
const files: File[] = Array.from({ length: 50 })
.fill(null)
.map(() => new File([], ""));
Я думаю, что приведенный выше код говорит само за себя. Мы генерируем макеты, чтобы увидеть, как ядро кода будет работать без реального доступа к вашему приложению.
Теперь основная часть:
const NUMBER_OF_PARALLEL_CALLS = 5;
const onFilePaymentSelect = (files: File[]) => {
const uploadQueue$ = from(files).pipe(
map(file => mockPayrollsService.sendFilesPaymentName(file)),
mergeAll(NUMBER_OF_PARALLEL_CALLS)
);
uploadQueue$
.pipe(
scan(nbUploadedFiles => nbUploadedFiles + 1, 0),
tap(nbUploadedFiles =>
console.log(`${nbUploadedFiles}/${files.length} file(s) uploaded`)
),
tap({ complete: () => console.log("All files have been uploaded") })
)
.subscribe();
};
onFilePaymentSelect(files);
- Мы используем
from
для отправки файлов один за другим в наблюдаемую - , используя
map
, мы подготавливаем наш запрос на 1 файл (но так как мы не подписываемся на него, и наблюдаемая становится холодной, запрос только что подготовлен, а не запущен!) - теперь мы используем
mergeMap
для запуска пула вызовов. Благодаря тому, что mergeMap
принимает параллелизм в качестве аргумента, мы можем сказать: «Пожалуйста, выполните максимум 5 вызовов одновременно» - , тогда мы используем
scan
только для отображения (для подсчета количество файлов, которые были успешно загружены)
Вот демонстрационная версия: https://stackblitz.com/edit/rxjs-zuwy33?file=index.ts
Откройте консоль, чтобы видите, мы не загружаем их все сразу