Эта задача является продолжением задачи promise-pool.
Допустим, теперь наша функция принимает не массив асинхронных функций, а массив URL, по которым нужно сделать запросы. В реальной жизни мы делали бы запрос с помощью стандартной функции fetch.
В той задаче функция для загрузки данных load
передается в качестве аргумента. Она принимает строку и возвращает промис, разрешающийся строкой. Можно считать, что для всех url load
что-то вернет.
const requestPromise = load("url1"); requestPromise.then(result => { console.log(result); // result — какая-то строка });
Необходимо реализовать функцию loadAll(urls, load, limit, cb)
, которая принимает массив строк urls
, загружает их с помощью функции load
и вызывает колбэк cb
с массивом результатов запросов по этим urls
. При этом есть два дополнительных требования:
limit
функций одновременно;cb
вызывается ровно один раз, когда мы собрали все ответы функции load
.Функция loadAll
не возвращает промис (она возвращается undefined
). Вместо этого в момент, кода все данные собраны необходимо вызвать колбэк cb
.
Пусть функция load работает разное время для разных URL: A — 2 секунды, B — 1 секунда, C — 1.4 секунды, D — 0.6 секунды, E — 1.2 секунды, F — 1.8 секунды, G — 0.8 секунды.
const urls = ["A", "B", "C", "A", "D", "B", "E", "B", "F", "G"]; loadAll(urls, 3).then((result) => { console.log(result); // массив с результатами });
При limit = 3 оптимальное время загрузки с учетом кэширования данных займет 3.4 секунды, т.к. мы не делаем запросы повторно.
A---------G--- B----D--F-------- C------E-----
Если бы не было кэширования, загрузка всех данных заняла бы 4.8 секунды, а диаграмма выглядела бы так:
A---------B----B---- B----A---------F-------- C------D--E-----G---
Это можно проверить, используя функцию run
из задачи promise-pool:
function loadAll(urls, load, limit, cb) { const fns = urls.map(url => () => load(url)); run(fns, limit).then(cb); } const url2duration = { A: 2000, B: 1000, C: 1400, D: 600, E: 1200, F: 1800, G: 800, }; const load = (url) => new Promise(resolve => setTimeout(resolve, url2duration[url], url)); const urls = ["A", "B", "C", "A", "D", "B", "E", "B", "F", "G"]; console.time("run"); loadAll(urls, load, 3, (result) => { console.log(result); console.timeEnd("run"); });