Cuando llamo a esta promesa, la salida no coincide con la secuencia de llamadas a funciones. El .then viene antes que el .catch , aunque la promesa con .then estaba siendo llamada después. ¿Cuál es la razón para eso?
const verifier = (a, b) => new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false))); verifier(3, 4) .then((response) => console.log("response: ", response)) .catch((error) => console.log("error: ", error)); verifier(5, 4) .then((response) => console.log("response: ", response)) .catch((error) => console.log("error: ", error));producción
node promises.js response: true error: falseEsta es una pregunta genial para llegar al fondo.
Cuando haces esto:
verifier(3,4).then(...) que devuelve una nueva promesa que requiere otro ciclo de regreso al bucle de eventos antes de que la promesa recién rechazada pueda ejecutar el controlador .catch() que sigue. Ese ciclo adicional da la siguiente secuencia:
verifier(5,4).then(...) una oportunidad de ejecutar su controlador .then() antes que el controlador .then() .catch() la línea anterior porque ya estaba en la cola antes de que el controlador .catch() del primero ingrese en la cola y los elementos se ejecuten desde la cola en orden FIFO .
Tenga en cuenta que si usa el .then(f1, f2) en lugar de .then().catch() , se ejecuta cuando lo espera porque no hay una promesa adicional y, por lo tanto, no hay una marca adicional involucrada:
const verifier = (a, b) => new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false))); verifier(3, 4) .then((response) => console.log("response (3,4): ", response), (error) => console.log("error (3,4): ", error) ); verifier(5, 4) .then((response) => console.log("response (5,4): ", response)) .catch((error) => console.log("error (5,4): ", error)); Tenga en cuenta que también etiqueté todos los mensajes para que pueda ver de qué llamada de verifier() provienen, lo que hace que sea mucho más fácil leer la salida.
Especificaciones de ES6 sobre el pedido de devolución de llamada prometido y una explicación más detallada
La especificación de ES6 nos dice que los "trabajos" de promesa (ya que llama a una devolución de llamada desde .then() o .catch() ) se ejecutan en orden FIFO en función de cuándo se insertan en la cola de trabajos. No nombra específicamente FIFO, pero especifica que los nuevos trabajos se insertan al final de la cola y los trabajos se ejecutan desde el principio de la cola. Eso implementa el pedido FIFO.
PerformPromiseThen (que ejecuta la devolución de llamada desde .then() ) conducirá a EnqueueJob, que es cómo se programa la ejecución real del controlador de resolución o rechazo. EnqueueJob especifica que el trabajo pendiente se agrega al final de la cola de trabajos. Luego, la operación NextJob extrae el elemento del frente de la cola. Esto garantiza el orden FIFO en los trabajos de servicio de la cola de trabajos de Promise.
Entonces, en el ejemplo de la pregunta original, obtenemos las devoluciones de llamada para la promesa del verifier(3,4) y la promesa del verifier(5,4) insertadas en la cola de trabajo en el orden en que se ejecutaron porque ambas promesas originales están hechas . Luego, cuando el intérprete regresa al ciclo de eventos, primero toma el trabajo del verifier(3,4) . Esa promesa se rechaza y no hay devolución de llamada para eso en el verifier(3,4).then(...) . Entonces, lo que hace es rechazar la promesa de que verifier(3,4).then(...) devolvió y eso hace que el verifier(3,4).then(...).catch(...) insertarse en la cola de trabajos.
Luego, vuelve al bucle de eventos y el siguiente trabajo que extrae de jobQueue es el trabajo del verifier(5, 4) . Eso tiene una promesa resuelta y un controlador de resolución, por lo que llama a ese controlador. Esto hace que se muestre la response (5,4): salida.
Luego, vuelve al ciclo de eventos y el siguiente trabajo que extrae de jobQueue es el verifier(3,4).then(...).catch(...) trabajo donde lo ejecuta y esto causa el error (3,4) salida que se mostrará.
Es porque el .catch() en la primera cadena es un nivel de promesa más profundo en su cadena que el .then() en la segunda cadena que causa el pedido que informó. Y es porque las cadenas de promesas se recorren de un nivel al siguiente a través de la cola de trabajos en orden FIFO, no sincrónicamente.
Recomendación general sobre confiar en este nivel de detalle de programación
FYI, en general, trato de escribir código que no dependa de este nivel de conocimiento de tiempo detallado. Si bien es curioso y ocasionalmente útil de entender, es un código frágil, ya que un simple cambio aparentemente inocuo en el código puede provocar un cambio en el tiempo relativo. Entonces, si el tiempo es crítico entre dos cadenas como esta, entonces preferiría escribir el código de una manera que fuerce el tiempo de la manera que quiero en lugar de confiar en este nivel de comprensión detallada.
Promise.resolve() .then(() => console.log('a1')) .then(() => console.log('a2')) .then(() => console.log('a3')) Promise.resolve() .then(() => console.log('b1')) .then(() => console.log('b2')) .then(() => console.log('b3'))En lugar de la salida a1, a2, a3, b1, b2, b3, verá a1, b1, a2, b2, a3, b3 por la misma razón: cada vez que devuelve una promesa, va al final del bucle de eventos. cola. Entonces podemos ver esta "carrera de promesa". Lo mismo ocurre cuando hay algunas promesas anidadas.