Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

171
Visualizações
Javascript Promises curiosity

When I call this promise, the output does not match with the sequence of function calls. The .then comes before the .catch, even though the promise with .then was being called after. What is the reason for that?

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));

output

node promises.js
response: true
error: false
over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

This is kind of a cool question to get to the bottom of.

When you do this:

verifier(3,4).then(...)

that returns a new promise which requires another cycle back to the event loop before that newly rejected promise can run the .catch() handler that follows. That extra cycle gives the next sequence:

verifier(5,4).then(...)

a chance to run its .then() handler before the previous line's .catch() because it was already in the queue before the .catch() handler from the first one gets in the queue and items are run from the queue in FIFO order.


Note, that if you use the .then(f1, f2) form in place of the .then().catch(), it does run when you expect it to because there's no additional promise and thus no additional tick involved:

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));

Note, I also labeled all the messages so you can see which verifier() call they come from which makes it a lot easier to read the output.


ES6 Spec on promise callback ordering and more detailed explanation

The ES6 spec tells us that promise "jobs" (as it calls a callback from a .then() or .catch()) are run in FIFO order based on when they are inserted into the job queue. It doesn't specifically name FIFO, but it specifies that new jobs are inserted at the end of the queue and jobs are run from the beginning of the queue. That implements FIFO ordering.

PerformPromiseThen (which executes the callback from .then()) will lead to EnqueueJob which is how the resolve or reject handler gets scheduled to be actually run. EnqueueJob specifies that the pending job is added at the back of the job queue. Then the NextJob operation pulls the item from the front of the queue. This ensures FIFO order in servicing jobs from the Promise job queue.

So, in the example in the original question, we get the callbacks for the verifier(3,4) promise and the verifier(5,4) promise inserted into the job queue in the order they were run because both those original promises are done. Then, when the interpreter gets back to the event loop, it first picks up the verifier(3,4) job. That promise is rejected and there's no callback for that in the verifier(3,4).then(...). So, what it does is reject the promise that verifier(3,4).then(...) returned and that causes the verifier(3,4).then(...).catch(...) handler to be inserted into the jobQueue.

Then, it goes back to the event loop and the next job it pulls from the jobQueue is the verifier(5, 4) job. That has a resolved promise and a resolve handler so it calls that handler. This causes the response (5,4): output to be shown.

Then, it goes back to the event loop and the next job it pulls from the jobQueue is the verifier(3,4).then(...).catch(...) job where it runs that and this causes the error (3,4) output to be shown.

It's because the .catch() in the 1st chain is one promise level deeper in its chain than the .then() in the 2nd chain that causes the ordering you reported. And, it's because promise chains are traversed from one level to the next via the job queue in FIFO order, not synchronously.


General Recommendation About Relying on This Level of Scheduling Detail

FYI, in general, I try to write code that does not depend upon this level of detailed timing knowledge. While it's curious and occasionally useful to understand, it is fragile code as a simple seemingly innocuous change to the code can lead to a change in the relative timing. So, if timing is critical between two chains like this, then I would rather write the code in a way that forces the timing the way I want it rather than rely on this level of detailed understanding.

over 4 years ago · Santiago Trujillo Relatório

0

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'))

Instead of output a1, a2, a3, b1, b2, b3 you will see a1, b1, a2, b2, a3, b3 because of the same reason - every then returns a promise and it goes to the end of the event-loop queue. So we can see this "promise race". The same is when there are some nested promises.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda