Normalmente, cuando una Promesa en JavaScript se rechaza sin manejar, obtenemos un error de unhandled promise rejection
manejado.
Pero entonces, ¿qué sucede con todas las promesas rechazadas ignoradas por la lógica Promise.race
? ¿Por qué no arrojan el mismo error?
Considere la siguiente prueba:
const normal = new Promise((resolve, reject) => { setTimeout(() => resolve(123), 100); }); const err = new Promise((resolve, reject) => { setTimeout(() => reject('ops'), 500); }); const test = Promise.race([normal, err]); test.then(data => { console.log(data); });
La prueba anterior simplemente genera 123
, pero no hay un error de unhandled promise rejection
no controlado para nuestra promesa de err
.
Estoy tratando de entender qué sucede con todas esas promesas rechazadas entonces, de ahí la pregunta.
Potencialmente terminamos con un montón de promesas sueltas que continúan ejecutándose en segundo plano, sin ningún tipo de manejo de errores y sin ningún informe sobre rechazos de promesas no manejados. Esto parece algo peligroso.
Caso en punto. Estaba tratando de implementar la lógica de combine
para iterables asincrónicos (similar a esto ), que requiere el uso de Promise.race
, mientras que al mismo tiempo rastreaba los rechazos de cualquier parámetro que se le pasara, porque la función de combine
necesita entonces rechazar en la siguiente solicitud .
Normalmente, cuando una Promesa en JavaScript se rechaza sin manejar, obtenemos un error de
unhandled promise rejection
manejado.
Sí, esto sucede cuando se rechaza una promesa que nunca había recibido la llamada .then()
para instalar controladores, es decir, una que es la promesa final de una cadena.
(Observe que .catch(onRejected)
delega internamente tot .then(undefined, onRejected)
, por lo que la promesa se marca como manejada de la misma manera).
Pero entonces, ¿qué sucede con todas las promesas rechazadas ignoradas por la lógica
Promise.race
? ¿Por qué no arrojan el mismo error?
Promise.race
llama a .then()
en todas las promesas en su argumento, marcándolas como manejadas:
Promise.race = function(thenables) { return new Promise((resolve, reject) => { for (const thenable of thenables) { Promise.resolve(thenable).then(resolve, reject); } }); };
Tenga en cuenta que no vuelve a generar el error cuando la promesa externa ya está resuelta, simplemente se ignora. Esto es por diseño: cuando usa Promise.race
, declara que solo está interesado en el primer resultado, y todo lo demás puede descartarse. Provocar rechazos de promesas no controlados de las promesas que no ganaron la carrera para bloquear su aplicación sería bastante perturbador.
Desde MDN :
El método Promise.race() devuelve una promesa que cumple o rechaza tan pronto como una de las promesas en un iterable cumple o rechaza, con el valor o la razón de esa promesa.
Su código cumple porque las llamadas de promesa más rápidas resolve
. Cámbialos y se rechaza.
const promise1 = new Promise((resolve, reject) => { setTimeout(resolve, 500, 'one'); }); const promise2 = new Promise((resolve, reject) => { setTimeout(reject, 100, 'two'); }); Promise.race([promise1, promise2]).then((value) => { console.log(value); }).catch((value) => { console.log('error ', value); });