Как реализовать задачу с одновременными запросами на сервер?
Всем привет, есть задача со следующими условиями:
1. Написать функцию, получающую на вход массив ссылок и число, указывающее максимальное количество одновременных запросов. 2. Одновременно должно выполняться не более указанного числа запросов. 3. Должен возвращаться массив результатов в той же последовательности, что и адреса запросов. 4. Нельзя делать повторные запросы на дублирующиеся адреса (при этом результат всё равно должен присутствовать в результирующем массиве). makeRequest([ 'url1', 'url2', 'url1', 'url3' ], 2).then(([ result1, result2, result1, result3 ]) => { }); Итак, моё решение: const removingDuplicates = (arr) => { return arr.filter((item, i, arr) => arr.indexOf(item) === i) } function makeRequests (urls, maxNumberRequests) { const uniqueUrls = removingDuplicates(urls); // console.log(uniqueUrls); let response = null; uniqueUrls.forEach(async (url, idx) => { // console.log('url', url, idx); if (idx === maxNumberRequests) { return false; } response = await fetch(url, { method: 'POST', body: "statistics", keepalive: true }); }); return response; } makeRequests([ 'url1', 'url2', 'url1', 'url3' ], 2); Собственно, подскажите, что мне нужно подправить, полагаю, что я не совсем правильно понял условие задачи. |
Имхо, у вас реализация удовлетворяет только первому условию, остальные мимо.
Цитата:
Цитата:
Цитата:
|
Я попытался написать.
У меня работало. Использовал GET вместо POST для удобства. Может сложновато получилось, но как есть const getpreq = async (areq, maxreq) => { const mres = new Map(); // Набор запросов, выполняемых в данный момент url => индекс const pres = []; // Массив, в который записываются обещания выполнения запросов // В виде {responce: Promise (выполнения запроса для уникальных) // Или {index: номер предыдущего запроса, для повторяющихся // Функция ожидает, когда можно быдет выполнять следующий запрос const mayaddreq = async () => { if (mres.size < maxreq) return true; // Формируем массив обещаний из выполняющихся запросов и ждем, когда какой-нибудь выполнится await Promise.any([... mres.values()].map (ind => pres[ind])) return true; } // Добавляет новый запрос const addreq = (i, url) => { let p = fetch(url, { // Обещание выполнение запроса method: 'GET', // body: "statistics", // keepalive: true }) let mp = p.then (res => { // Кошда запрос выполнится mres.delete(url); // Удалить его из списка выполняемых return {responce:res} // Вернуть ответ }) mres.set (url, i) // Записать в список выполняемых return mp // Возвращаем обещание } for (let i= 0; i< areq.length; i++) { const url = areq[i]; let si = areq.indexOf(url) if (si>=0 && si < i) { // Это повторяющийся запрос pres.push( {index:si}) } else { await mayaddreq () // Ждем, когда можно начать выполнять pres.push (addreq (i, url)) // Выполняем запрос и записываем обещание в массив } } return pres } // Функция получает массив вида [{responce: ответ responce от fetch} или {index: номер исходного responce для повторяющихся} ...] // Возвращает массив результатов обработки responce const getans = async (aresp) => { let aansp = [] // массив обещаний обработки responce aresp.forEach ((r, i, ar) => { // в данном случае я использую responce.text aansp[i] = r.responce? r.responce.text() : Promise.resolve(aansp[r.index]) }) return Promise.all (aansp) } aurls = [ 'testaj.php?num=1&val=10', 'testaj.php?num=2&val=20', 'testajm.php?num=3&val=30', 'testajm.php?num=4&val=40', 'testaj.php?num=5&val=50', 'testajm.php?num=6&val=60', 'testaj.php?num=7&val=70', 'testajm.php?num=6&val=60', 'testaj.php?num=2&val=20', 'testajm.php?num=6&val=60', 'testajm.php?num=3&val=30', 'testajm.php?num=8&val=80', 'testajm.php?num=8&val=80', 'testajm.php?num=8&val=80', 'testaj.php?num=9&val=90', 'testaj.php?num=1&val=10', ] const main = async () => { let prec = await getpreq (aurls, 5) let aresp = await Promise.all (prec) let ans = await getans (aresp) console.log (ans) } main() Зы Предполагается, что запросы выполняются без ошибок. С обработкой ошибок сложнее будет. |
такие штуковины надо делать в параметризуемом виде.
вот, с обработкой ошибок // запускатель асинхронной функции для параметров /* args: { request: param => Promise getKey: param => value limit: number params: array } return [...] */ function runRequests(args) { if (!args.params) { return Promise.resolve([]); } return new Promise(res => { const results = new Array(args.params.length); const map = new Map(); const req = [] for (let i = 0; i < args.params.length; ++i) { const param = args.params[i]; const key = args.getKey ? args.getKey(param) : param; let config = map.get(key); if (!config) { config = { param: param, indexes: [i] }; map.set(key, config); req.push(config); } else { config.indexes.push(i); } } const limit = Math.min(args.limit || req.length, req.length); let pos = 0; let doneCount = 0; function run() { if (pos < req.length) { const config = req[pos++]; args.request(config.param).then( data => done(false, data, config), error => done(true, error, config)) } } function done(error, value, config) { // результат в комплексном виде, тут может быть как успешно, так и с ошибкой const item = { success: !error, data: error ? undefined : value, error: error ? value : undefined }; for (let i = 0; i < config.indexes.length; ++i) { results[config.indexes[i]] = item } doneCount++; if (doneCount >= req.length) { res(results); } else { run(); } } for (let i = 0; i < limit; ++i) { run(); } }); } // пример асинхронной функции, которая получает параметр и возвращает промис function asyncReverse(value) { console.log('request ', value); return new Promise((res, rej) => { const r = Math.random(); const delay = Math.floor(2000 + 3000 * Math.random()); setTimeout(() => { if (r < 0.00002) { rej(r); } else { console.log('result for ', value); res(value.split('').reverse().join('')); } }, delay); }); } // запуск для параметров runRequests({ request: asyncReverse, // асинхронная функция getKey: param => param, // ключ, по которому выявляем одинаковые параметры limit: 3, params: [ '1234', 'qazx', 'rwsxc', 'edcv', 'rfvb', 'edcv' ] }).then(console.log) смотреть в консоли результат можно |
Всем спасибо за помощь.
|
Часовой пояс GMT +3, время: 06:53. |