Estaba escribiendo polyfill para el método Promise.race() usando el siguiente fragmento de código.
const promise = new Promise((resolve, reject) => { resolve('promise resolved'); }); const promise2 = Promise.resolve('promise2 resolved'); function raceCopy(promises) { return new Promise(function (resolve, reject) { for (var index = 0; index < promises.length; index++) { Promise.resolve(promises[index]) .then(resolve) .catch(reject); } }); } raceCopy([Promise.reject('copy rejected'), promise, promise2]) .then((response) => console.log(response)) .catch((error) => console.error(error));Pero en lugar de dar el error "copia rechazada" en la consola, muestra "promesa resuelta". No entiendo ¿Cómo y por qué está funcionando así?
¿Qué probé?
Promise.race([Promise.reject('copy rejected'), promise, promise2]) .then((response) => console.log(response)) .catch((error) => console.error(error));raceCopy() . Algo como esto, function raceCopy(promises) { return new Promise(function (resolve, reject) { for (var index = 0; index < promises.length; index++) { Promise.resolve(promises[index]).then(resolve, reject); } }); }Y también está dando el resultado correcto.
¿Qué no estoy entendiendo? Si todas las implementaciones son iguales, ¿por qué los resultados no son los mismos para todas? ¿Que me estoy perdiendo aqui?
Hice algunas pruebas y encontré resultados interesantes. Tenga en cuenta que esto es solo algo que descubrí haciendo pruebas, por lo que podría no ser 100% exacto; una inmersión profunda en la documentación de Ecmascript sería más correcta con seguridad.
Básicamente, la razón por la que su código original no funciona es por el encadenamiento de .then y .catch . Es debido a cómo se ponen en cola las microtareas en esta situación. Vamos a mostrar un ejemplo usando la siguiente entrada:
var promises = [Promise.reject('rejected'), Promise.resolve('resolved')];si en tu código usas encadenamiento, este es el resultado:
Promise.resolve(promises[index]) .then(resolve) .catch(reject) /* ----------------------- Microtask queue ----------------------- - .then of index 0, then enqueue the catch - .then of index 1 (which resolve the promises) - .catch of index 0 (which gets ignored) ------------------------------------------------------------ If we reverse the chaining */ Promise.resolve(promises[index]) .catch(reject) .then(resolve) /* ----------------------- Microtask queue ----------------------- - .catch of index 0 (which reject the promises) and don't enqueue following .then - .then of index 1 (which gets ignored) */ El primer .catch termina al final de la cola de microtareas porque se puso en cola en la primera microtarea, mientras que los otros .then están todos en cola en la tarea principal desde el principio.
Esto es solo especulación, pero creo que funciona de esta manera para permitir que un solo .catch errores incluso si hay varios .then antes.
La forma correcta de solucionarlo es probablemente la que ya encontraste en tu último ejemplo. Al usar solo uno, .then en cola una microtarea y la manejará de la manera correcta.