Recentemente, encontrei esta pergunta no Stack Overflow, perguntando sobre como o método then realmente funciona em JavaScript. O respondente, Trincot, fez o seguinte comentário:
O host verificará quais filas de trabalhos possuem entradas, dando preferência às filas de trabalhos com alta prioridade. Uma fila de tarefas do Promise tem uma prioridade muito alta, normalmente mais alta do que a fila de eventos que lida com a interação do usuário ou outros eventos externos. Portanto, o trabalho que foi colocado na fila na etapa 4 acima é retirado da fila Promise Job. Este trabalho chamará sequencialmente as funções de retorno de chamada que foram registradas como retornos de chamada (como o registrado na etapa 7) no objeto myPromise.
Se entendi sua explicação corretamente, sempre que a função resolve é invocada, o JavaScript agendará uma microtarefa (ou um job) na fila de jobs, que executará todos os callbacks passados para eles, incluindo o encadeamento, quando a pilha de chamadas estiver vazia. Por exemplo:
Promise.resolve("Hi")
.then(() => {
console.log("Hi");
})
.then(() => {
console.log("World");
});
Nesse caso, a promessa é resolvida imediatamente, o que significa que uma microtarefa será agendada imediatamente. Quando os retornos de chamada terminarem a execução, o mecanismo JS verificará se há microtarefas na fila. Como a promessa foi resolvida imediatamente, ele executará a microtarefa, que por sua vez executa todos os manipuladores passados para o método then. Como resultado, o código produzirá "Hi" e "World".
No entanto, por que esse código gera "1 3 2 4" em vez de "1 2 3 4"?
const p1 = Promise.resolve();
const p2 = Promise.resolve();
p1.then(() => {
console.log(1);
}).then(() => {
console.log(2);
});
p2.then(() => {
console.log(3);
}).then(() => {
console.log(4);
});
Acredito que o código deve gerar "1 2 3 4" em vez de "1 3 2 4". Isso ocorre porque, quando p1 e p2 são resolvidos, duas microtarefas são enfileiradas. À medida que os retornos de chamada terminam a execução, eles adicionam esses retornos de chamada às suas listas internas. Assim que a pilha de chamadas estiver vazia, o mecanismo JS seleciona a tarefa mais antiga da fila e a executa. Essa tarefa deve executar todos os manipuladores passados para essa instância específica do Promise. No entanto, não parece estar acontecendo como o esperado. Alguém poderia me explicar o motivo desse comportamento?
Obrigado pelo seu tempo e tenha um ótimo dia!
Isso é um mal-entendido. Uma microtarefa (uma tarefa prometida) é enfileirada quando:
then
método é executado em uma promessa resolvidathen
método executado nela antes de ser resolvida: para cadathen
retorno de chamada, um trabalho separado é criado.Portanto, quando as duas primeiras instruções forem executadas, nada será adicionado à fila de jobs de promessa ainda.
Perceba que:
then
método é executado, seu retorno de chamada é colocado na fila de jobs de promessa somente quando a promessa já foi resolvida. Caso contrário, ele é registrado em espera pela promessa de resolução.then
método é executado, ele retorna uma promessa que está sempre pendente, mesmo quando é chamado em uma promessa resolvida.Pode ajudar a identificar as promessas retornadas por
then()
chamadas com uma variável e também nomear as funções de retorno de chamada.Isso deixaria seu script assim:
Aqui está uma visão simplificada sobre o que acontece nesse script:
?
significa que está pendente;F
significa que está cumprido.p1 = Promise.resolve()
p2 = Promise.resolve()
q1 = p1.then(p1_then)
p1_then
r1 = q1.then(q1_then)
p1_then
q2 = p2.then(p2_then)
p1_then
,p2_then
r2 = q2.then(q2_then)
p1_then
,p2_then
p1_then
p2_then
p1_then
console.log(1)
p2_then
p1_then
p2_then
,q1_then
p2_then
q1_then
p2_then
console.log(3)
q1_then
p2_then
q1_then
,q2_then
q1_then
q2_then
q1_then
console.log(2)
q2_then
q1_then
q2_then
q2_then
q2_then
console.log(4)
q2_then
Segue a ordem de execução:
então a ordem do processo será 1,3,2,4
Lembre-se de que, embora o código pareça síncrono, a resolução do Promise e a execução dos manipuladores .then() são processos assíncronos.