#javascript #node.js #async-await #es6-promise
#javascript #node.js #async-ожидание #es6-обещание
Вопрос:
Я пытаюсь запускать параллельные запросы в пакетах к API, используя набор ключевых слов в массиве. Статья Дениса Фатхудинова.
Проблема, с которой я сталкиваюсь, заключается в том, что для каждого ключевого слова мне нужно снова запускать запрос с другим page
аргументом столько раз, сколько число в pages
переменной.
Я продолжаю получать Cannot read property 'then' of undefined
для возврата chainNext
функции.
Параллельный запрос в пакетах сам по себе, без цикла for, отлично работает, я изо всех сил пытаюсь включить цикл for в процесс.
// Parallel requests in batches
async function runBatches() {
// The keywords to request with
const keywords = ['many keyword strings here...'];
// Set max concurrent requests
const concurrent = 5;
// Clone keywords array
const keywordsClone = keywords.slice()
// Array for future resolved promises for each batch
const promises = new Array(concurrent).fill(Promise.resolve());
// Async for loop
const asyncForEach = async (pages, callback) => {
for (let page = 1; page <= pages; page ) {
await callback(page);
}
};
// Number of pages to loop for
const pages = 2;
// Recursively run batches
const chainNext = (pro) => {
// Runs itself as long as there are entries left on the array
if (keywordsClone.length) {
// Store the first entry and conviently also remove it from the array
const keyword = keywordsClone.shift();
// Run 'the promise to be' request
return pro.then(async () => {
// ---> Here was my problem, I am declaring the constant before running the for loop
const promiseOperation = await asyncForEach(pages, async (page) => {
await request(keyword, page)
});
// ---> The recursive invocation should also be inside the for loop
return chainNext(promiseOperation);
});
}
return pro;
}
return await Promise.all(promises.map(chainNext));
}
// HTTP request
async function request(keyword, page) {
try {
// request API
const res = await apiservice(keyword, page);
// Send data to an outer async function to process the data
await append(res.data);
} catch (error) {
throw new Error(error)
}
}
runBatches()
Ответ №1:
Проблема просто в том, что pro не определен, потому что вы его не инициализировали.
Вы в основном выполняете этот код:
Promise.all(new Array(concurrent).fill(Promise.resolve().map(pro => {
// pro is undefined here because the Promise.resolve had no parameter
return pro.then(async () => {})
}));
Я не совсем уверен в вашей идее, стоящей за этим, но это ваша проблема в более сжатой версии.
Комментарии:
1. Изначально это должно было быть неопределенным, я взял пакетный код из itnext.io / … и там также написано undefined, но затем они заполняются, и все работает нормально
Ответ №2:
Я заставил его работать, переместив фактический запрос promiseOperation
внутрь цикла for и вернув туда рекурсивную функцию
// Recursively run batches
const chainNext = async (pro) => {
if (keywordsClone.length) {
const keyword = keywordsClone.shift()
return pro.then(async () => {
await asyncForEach(pages, (page) => {
const promiseOperation = request(keyword, page)
return chainNext(promiseOperation)
})
})
}
return pro
}
Заслуга за параллельные запросы в пакетах принадлежитhttps://itnext.io/node-js-handling-asynchronous-operations-in-parallel-69679dfae3fc