Почему этот пример генерирует UnhandledPromiseRejectionWarning? - PullRequest
0 голосов
/ 18 октября 2018

NodeJS версии 8.11 - предупреждение: «Эта ошибка возникла либо из-за того, что внутри асинхронной функции возникла ошибка без блока catch, либо из-за отклонения обещания, которое не было обработано с помощью .catch ().»

Ни то, ни другоеиз них истина, которую вы можете увидеть, проверив мой тестовый пример:

const DEMONSTRATE_FAILURE = false

async function doPromises() {
    try {
        if (DEMONSTRATE_FAILURE) {
            // This causes UnhandledPromiseRejectionWarning warnings:

            const brokenPromises = [createPromises(), createPromises()]

            await brokenPromises[0]
            await brokenPromises[1]

        } else {
            // This works fine:
            await createPromises()
            await createPromises()
        }
    } catch(err) {
        process.stdout.write("x")
    }
}

// Create 10 promises, of which 50% will reject after between 0 and 1000ms
function createPromises() {
    let badPromises = []
    for (let x = 0; x < 10; x++) {
        badPromises.push(new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() > 0.5) {
                process.stdout.write("-")
                reject("rejected!")
            } else {
                process.stdout.write("+")
                resolve()
            }
        }, Math.round(Math.random() * 1000))
        }))
    }

    return Promise.all(badPromises)
}


(async function main() {
    while (true) {
        await doPromises()
    }
})()

Установите флаг DEMONSTRATE_FAILURE, чтобы увидеть, что один и тот же код работает с ошибкой и без нее.

1 Ответ

0 голосов
/ 18 октября 2018

Проблема в том, что, как только один await ed Promise отклоняет запрос, выдается ошибка, и код перемещается из строки await brokenPromises[0] внутри try в catch.Итак, ошибка, выданная brokenPromises[0], теперь правильно перехвачена.Но отклоненный Promise в brokenPromises[1] не был обработан!(Это было бы обработано , если бы блок try прошел [0] и достиг [1], а затем await brokenPromises[0] вызвал бы ошибку, которая была бы обнаружена, но интерпретаторне знает этого)

Вот гораздо меньший пример, иллюстрирующий исходную проблему (откройте консоль браузера, чтобы увидеть отклонение, оно не отображается в консоли Stack Snippet):

const makeProm = () => new Promise((_, reject) => setTimeout(reject, 500));

console.log('will be uncaught:');
// Unhandled rejection:
(async () => {
  try {
    const proms = [makeProm(), makeProm()];
    await proms[0];
    await proms[1];
  } catch(e){}
})();

// Works:
setTimeout(async () => {
  console.log('going to be caught:');
  try {
    await makeProm();
    await makeProm();
  } catch(e){ console.log('caught'); }
}, 1000);

Вы можете исправить это, await используя Promise.all из обоих Promise с вместо await каждого Promise по отдельности - таким образом,когда выбрасывается Promise.all, обе отклоненные цепочки Promise были обработаны.

Изменение здесь process.stdout.write s на console.log s, чтобы исправить это, можно было показать в исполняемом фрагменте:

const DEMONSTRATE_FAILURE = true;

async function doPromises() {
  try {
    if (DEMONSTRATE_FAILURE) {
      // This causes UnhandledPromiseRejectionWarning warnings:

      const brokenPromises = [createPromises(), createPromises()]
      await Promise.all(brokenPromises);

    } else {
      // This works fine:
      await createPromises()
      await createPromises()
    }
  } catch (err) {
    console.log("x")
  }
}

// Create 10 promises, of which 50% will reject after between 0 and 1000ms
function createPromises() {
  let badPromises = []
  for (let x = 0; x < 10; x++) {
    badPromises.push(new Promise((resolve, reject) => {
      setTimeout(() => {
        if (Math.random() > 0.5) {
          console.log("-")
          reject("rejected!")
        } else {
          console.log("+")
          resolve()
        }
      }, Math.round(Math.random() * 1000))
    }))
  }

  return Promise.all(badPromises)
}


(async function main() {
    await doPromises()
})()
...