Избегайте использования await в цикле for, когда результат Promise обновляет саму переменную цикла итерации.

Есть ли способ не использовать внутренний цикл ожидания для следующего кода?

      const redirects = ['redirectId1'];

for (let i = 0; i < redirects.length; i++) {
  const promiseResult = await anAsyncFunction(redirects[i]);
  
  if (promiseResult.redirects) {
    redirects.forEach(newRedirect => {
      if (!redirects.includes(newRedirect)) redirects.push(newRedirect);
    });
  }
}

Я пробовал использовать карту

      const redirects = ['redirectId1'];

const promiseArr = redirects.map(async redirect => {
  const promiseResult = await anAsyncFunction(redirect);

  if (promiseResult.redirects) {
    redirects.forEach(newRedirect => {
      if (!redirects.includes(newRedirect)) redirects.push(newRedirect);
    });
  }
});

await Promise.all(promiseArr);

но при этом код выполняется дальше, прежде чем newRedirect помещается в массив перенаправлений, поэтому не вызывает anAsyncFunction для новой добавленной стоимости.

Я хочу знать, есть ли какой-нибудь способ добиться этого?

2 ответа

Если идея состоит в том, чтобы отправлять каждый запрос как можно скорее, не дожидаясь разрешения более ранних запросов, вы можете использовать рекурсивную асинхронную функцию, которая вызывает себя, когда результат содержит перенаправления:

      const recurse = (redirects) => Promise.all(
  redirects.map(r => anAsyncFunction(r)
    .then(({ redirects }) => {
      if (redirects) {
        return recurse(redirects);
      }
    })
  )
);
// pass in the initial array:
await recurse(redirects);

Если вам также нужно использовать заполненный внешний redirects массив позже, тогда:

      const recurse = (redirects) => Promise.all(
  redirects.map(r => anAsyncFunction(r)
    .then(({ redirects }) => {
      return redirects
        ? recurse(redirects).then(res => [redirects, res])
        : [];
    })
  )
);
// pass in the initial array:
const allRedirects = [initialRedirects, await recurse(initialRedirects)].flat(Infinity);

Если вы заинтересованы в том, чтобы каждый пакет перенаправления работал параллельно и продолжал запрашивать дополнительные перенаправления, пока они есть, вы можете добиться этого следующим образом:

      const handleRedirects = async (_redirects) => {
  const newRedirects = [];
  await Promise.all(
    _redirects.map(async (redirect) => {
      const promiseResult = await anAsyncFunction(redirect);

      if (promiseResult.redirects) {
        promiseResult.redirects.forEach((newRedirect) => {
          if (!_redirects.includes(newRedirect)) newRedirects.push(newRedirect);
        });
      }
    })
  );
  return newRedirects;
};


const run = async () => {
  const redirects = ['redirectId1'];
  let newRedirects = [ ...redirects ];
  do {
    newRedirects = await handleRedirects(newRedirects);
    redirects.push(...newRedirects);
  } while (newRedirects.length)
}
Другие вопросы по тегам