Cuando llamo a esta promesa, la salida no coincide con la secuencia de llamadas a funciones. El .then
viene antes del .catch
, aunque la promesa con .then
se llama 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));
salida
node promises.js
response: true
error: false
javascript
node.js
Gustavo Alves
fuente
fuente
Respuestas:
Esta es una pregunta interesante 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
.catch()
controlador que sigue. Ese ciclo adicional da la siguiente secuencia:verifier(5,4).then(...)
una oportunidad de ejecutar su
.then()
controlador antes que la línea anterior.catch()
porque ya estaba en la cola antes de que el.catch()
controlador de la primera entra en la cola y los elementos se ejecutan desde la cola en orden FIFO.Tenga en cuenta que si usa el
.then(f1, f2)
formulario en lugar del.then().catch()
, se ejecuta cuando lo espera porque no hay ninguna promesa adicional y, por lo tanto, no hay ninguna 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é
verifier()
llamada provienen, lo que hace que sea mucho más fácil leer el resultado.ES6 Spec sobre pedido de devolución de llamada de promesa y explicación más detallada
La especificación ES6 nos dice que los "trabajos" de promesa (como llama a una devolución de llamada desde a
.then()
o.catch()
) se ejecutan en orden FIFO según el momento en que se insertan en la cola de trabajos. No nombra específicamente a 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 la ordenación FIFO.PerformPromiseThen (que ejecuta la devolución de llamada desde
.then()
) conducirá a EnqueueJob, que es la forma en que se programa la ejecución 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 asegura 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
verifier(3,4)
promesa y laverifier(5,4)
promesa insertadas en la cola de trabajos en el orden en que se ejecutaron porque ambas promesas originales se cumplieron. Luego, cuando el intérprete vuelve al bucle de eventos, primero retoma elverifier(3,4)
trabajo. Esa promesa se rechaza y no hay devolución de llamada para eso en elverifier(3,4).then(...)
. Entonces, lo que hace es rechazar la promesa queverifier(3,4).then(...)
regresó y que hace que elverifier(3,4).then(...).catch(...)
controlador se inserte en jobQueue.Luego, vuelve al bucle de eventos y el siguiente trabajo que extrae de jobQueue es el
verifier(5, 4)
trabajo. Eso tiene una promesa resuelta y un controlador de resolución, por lo que llama a ese controlador. Esto haceresponse (5,4):
que se muestre la salida.Luego, vuelve al bucle de eventos y el siguiente trabajo que extrae de jobQueue es el
verifier(3,4).then(...).catch(...)
trabajo donde lo ejecuta y esto haceerror (3,4)
que se muestre el resultado.Es porque
.catch()
en la 1ª cadena hay un nivel de promesa más profundo en su cadena que.then()
en la 2ª cadena que provoca el pedido que informó. Y es porque las cadenas de promesa se atraviesan de un nivel al siguiente a través de la cola de trabajos en orden FIFO, no de forma sincrónica.Recomendación general sobre la confianza en este nivel de detalle de la programación
Para su información, en general, trato de escribir código que no dependa de este nivel de conocimiento detallado del tiempo. 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 conducir a un cambio en el tiempo relativo. Entonces, si el tiempo es crítico entre dos cadenas como esta, entonces prefiero 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.
fuente
.then()
tiene que devolver una nueva promesa que debe resolver / rechazar asincrónicamente en un futuro tick que es lo que conduce a este pedido. ¿Conoce alguna implementación que no utilice el orden FIFO de las devoluciones de llamada de la competencia?await
embargo, ES11 cambió el comportamiento de ).PerformPromiseThen
conducirá aEnqueueJob
cuál es la forma en que se programa la llamada al 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 principio de la cola. Esto asegura el orden FIFO en la cola de trabajos de Promise.await
en ES11? Basta con un enlace. ¡¡Gracias!!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 entonces devuelve una promesa y va al final del ciclo de eventos. cola. Entonces podemos ver esta "carrera de promesas". Lo mismo ocurre cuando hay algunas promesas anidadas.
fuente