Descubrí un problema extraño al intentar implementar una función que espera todas las promesas de una matriz y detecta todos los errores. Esta implementación condujo a un bloqueo completo de la aplicación causado por un rechazo de promesa no controlado.
const completeAllPromises = async (promises) => { const errors = [] for (let i = 0; i < promises.length; i++) { await promises[i].catch((error) => { error.message = `${i}: ${error.message}` errors.push(error) }) } if (errors.length) return Promise.reject(errors) } const timeout = (duration) => { return new Promise((resolve) => setTimeout(() => resolve()), duration) } const fail = async () => { return Promise.reject(new Error('Failed')) } const crash = async () => { await completeAllPromises([timeout(100), fail()]).catch( (error) => console.log(`Crash prevented, catch promise rejection`, error), // never be called ) } const main = async () => { // will crash and catch will not be called await crash().catch((error) => console.log('Finished crash() and catch error', error)) } main() Parece que la implementación de catch en la función completeAllPromises se ejecuta en tiempo de ejecución, por lo que mientras espera la primera promesa de tiempo de espera, fail() rechazará y no será catch. Lo extraño para mí es que crash() y no main() detectarán este error. Casi parece que la cadena de llamadas no se puede resolver en el momento en que fail() rechaza.
Cambiar timeout(100) y fail() resultará en una captura adecuada de errores. El uso de un bloque de prueba y captura también conducirá al mismo problema.
const completeAllPromises = async (promises) => { const errors = [] const results = await Promise.allSettled(promises) results.forEach((result) => { if (result.status === 'rejected') errors.push(result.reason) }) if (errors.length) return Promise.reject(errors) } const timeout = (duration) => { return new Promise((resolve) => setTimeout(() => resolve()), duration) } const fail = async () => { return Promise.reject(new Error('Failed')) } const crash = async () => { await completeAllPromises([timeout(100), fail()]).catch( (error) => console.log(`Crash prevented, catch promise rejection`, error), // never be called ) } const main = async () => { // will crash and catch will not be called await crash().catch((error) => console.log('Finished crash() and catch error', error)) } main()