Множественные ожидания внутри try catch not catch error - PullRequest
1 голос
/ 27 мая 2020

Я работаю над проектом, который включает ежедневное обновление всей коллекции mongoDB. Я делаю несколько асинхронных вызовов, поэтому решаю использовать async / await и try / catch. Мой код выглядит так:

const updateMongoData = async () => {
  try {
    const data = await getData(); //This is the new data that I am using to update Mongo docs
    const countries = await GlobalData.find();
    countries.forEach(async (row) => {
      const res = await Global.updateOne(
        { country: row.country },
        {
          //Use data
          lastUpdated: Date.now(),
        }
      );
    });
  } catch (err) {
    console.log(err);
  }
};

Все работает нормально, кроме случаев, когда я делаю синтаксическую ошибку, например, Dated.now() вместо Date.now(). Это даст мне сообщение об ошибке:

(node:8248) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 368)

Я попытался вставить другой try catch вместо моего forEach и переместил forEach внутрь, и это, похоже, отловило синтаксическую ошибку. Почему это работает? И как это сделать наиболее аккуратно?

GlobalData.find()
  .then(countries => { 
    countries.forEach(async (row) => {
     try{ 
       const res = await Global.updateOne(
        { country: row.country },
        {
          //Use data
          lastUpdated: Date.now(),
        }
      );
     }
     catch(err){
       console.log(err);
     } 
   })
 }).catch(err => console.log(err));

1 Ответ

3 голосов
/ 27 мая 2020

Ваш try catch не может поймать ReferenceError, вызванный изменением Date на Dated, потому что catch требует вызова неявного обработчика reject цепочки async / await Promise. Ошибки, возникшие внутри Array.prototype.forEach, не увидят этот обработчик.

Вы можете думать о Array.prototype.forEach как о методе, который запускает множество неконтролируемых выполнений; ни один из них не предназначен для ожидания от родительской области.

Вместо этого вы можете использовать Promise.all и Array.prototype.map, чтобы поймать ошибку.

const updateMongoData = async () => {
  try {
    const data = await getData(); //This is the new data that I am using to update Mongo docs
    const countries = await GlobalData.find();
    await Promise.all(countries.map(async (row) => {
      const res = await Global.updateOne(
        { country: row.country },
        {
          //Use data
          lastUpdated: Dated.now(),
        }
      );
    }))
  } catch (err) {
    console.log('yo', err);
  }
};

updateMongoData() // > yo ReferenceError: Dated is not defined

Ваш второй пример работает, потому что * Блок 1019 * catch имеет ту же область видимости, что и блок Array.prototype.forEach. Однако, если вы переместите этот оператор try catch наружу, он не увидит ошибки.

Есть другой способ использования проекта , который я начал. Взносы приветствуются.

const { pipe, fork, map, tryCatch } = require('rubico')

const updateGlobalByCountry = (country, data) => Global.updateOne(
  { country },
  { lastUpdated: Date.now() }, // <- use data
)

const updateMongoData = tryCatch(
  pipe([
    fork({
      data: getData, // () => data
      countries: GlobalData.find, // () => countries
    }), // () => ({ data, countries })
    ({ data, countries }) => map(
      country => updateGlobalByCountry(country, data)
    )(countries), // ({ data, countries }) => updatedCountries
  ]),
  err => console.log(err),
)
...