Параллельные HTTP-запросы в пакетах с циклом async for для каждого запроса

#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