let x = 0;
async function test() {
x += await 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Os valores de x
logado são 1
e 5
. Minha pergunta é: por que o valor do x
5
segundo log?
Se o test
é executado depois x += 1
(já que é uma função assíncrona), o valor de x é 1 no momento em que test
é executado, portanto x += await 5
deve ser o valor de x
6
.
javascript
async-await
event-loop
ALDRIN P VINCENT
fonte
fonte
await (x += 5)
ex += await 5
.Respostas:
TL; DR: Porque
+=
lêx
antes, mas grava após alterar, devido àawait
palavra - chave em seu segundo operando (lado direito).async
As funções são executadas de forma síncrona quando foram chamadas até a primeiraawait
instrução.Portanto, se você remover
await
, ele se comportará como uma função normal (com a exceção de que ainda retorna uma promessa).Nesse caso, você obtém
5
e6
no console:A primeira
await
interrompe a execução síncrona, mesmo que seu argumento esteja disponível de forma síncrona; portanto, o seguinte retornará1
e6
, conforme o esperado:No entanto, seu caso é um pouco mais complicado.
Você colocou
await
dentro de uma expressão que usa+=
.Você provavelmente sabe que em JS
x += y
é idêntico ax = (x + y)
. Usarei o último formulário para entender melhor:Quando o intérprete chega a esta linha ...
... começa a avaliar e passa a ...
... então, chega ao
await
e para.O código após a chamada da função começa a ser executado, modifica o valor de
x
e registra-o.x
é agora1
.Depois que o script principal é encerrado, o intérprete retorna à
test
função em pausa e continua avaliando essa linha:E, como o valor de
x
já está substituído, ele permanece0
.Finalmente, o intérprete faz a adição, lojas
5
parax
, e registra-lo.Você pode verificar esse comportamento efetuando login em um getter / setter de propriedade de objeto (neste exemplo,
y.z
reflete o valor dex
:fonte
x += y
é idêntico ax = (x + y)
". - Este não é o caso em todas as situações em todos os idiomas, mas em geral você pode contar com eles agindo da mesma maneira.Sua declaração
x += await 5
deseja queO
_temp
valor do orary é0
e, se você alterarx
durante oawait
(que é o seu código), não importa, ele será atribuído5
posteriormente.fonte
Esse código é bastante complexo a seguir, pois leva alguns saltos assíncronos inesperados para frente e para trás. Vamos examinar (perto de) como ele realmente será executado e explicarei o porquê posteriormente. Também alterei os logs do console para adicionar um número - facilita a referência a eles e também mostra melhor o que é registrado:
Portanto, o código não está indo exatamente de maneira direta, com certeza. E nós temos uma
4/7
coisa estranha também. E isso é realmente a totalidade do problema aqui.Antes de tudo, vamos esclarecer - as funções assíncronas não são estritamente assíncronas. Eles apenas pausariam a execução e continuariam mais tarde se a
await
palavra-chave fosse usada. Sem ele, eles executam de cima para baixo, expressão após expressão de forma síncrona:Portanto, a primeira coisa que precisamos saber é que o uso
await
fará com que o restante da função seja executado posteriormente. No exemplo dado, isso significa queconsole.log('x1 :', x)
será executado após o restante do código síncrono. Isso ocorre porque qualquer promessa será resolvida após a conclusão do loop de eventos atual.Portanto, isso explica por que somos
x2 : 1
registrados primeiro e por quex2 : 5
é registrado depois, mas não por que o último valor é5
. Logicamentex += await 5
deveria ser5
... mas aqui está a segunda captura daawait
palavra-chave - ela fará uma pausa na execução da função, mas qualquer coisa antes que ela já tenha sido executada.x += await 5
será realmente processado da seguinte maneirax
. No momento da execução, é isso0
.await
a próxima expressão que é5
. Portanto, a função pausa agora e será retomada mais tarde.0 + 5
x
Assim, as pausas função, depois de ler que
x
é0
e recomeça quando ele já mudou, no entanto, ele não re-ler o valorx
.Se desembrulhar o
await
noPromise
equivalente que iria executar, você tem:fonte
É um pouco complicado o que realmente está acontecendo: as duas operações de adição estão acontecendo paralelamente, portanto a operação seria como:
Dentro da promessa:
x += await 5
==>x = x + await 5
==>x = 0 + await 5
==>5
Fora:
x += 1
==>x = x + 1
==>x = 0 + 1
==>1
uma vez que todas as operações acima estão acontecendo da esquerda para a direita, a primeira parte da adição pode ser calculada ao mesmo tempo e, como há um período de espera antes de 5, a adição pode demorar um pouco. Você pode ver a execução colocando o ponto de interrupção no código.
fonte
Async e Await são extensões de promessas. Uma função assíncrona pode conter uma expressão de espera que interrompe a execução da função assíncrona e aguarda a resolução da Promessa aprovada e, em seguida, retoma a execução da função assíncrona e retorna o valor resolvido. Lembre-se de que a palavra-chave wait é válida apenas dentro de funções assíncronas.
Mesmo que você tenha alterado o valor de x após chamar a função de teste, o valor de x permanecerá 0, pois a função assíncrona já criou sua nova instância. Significando que tudo muda na variável fora dela não altera o valor dentro dela depois que foi chamado. A menos que você coloque seu incremento acima da função de teste.
fonte
let x="Didn't receive change"; (async()=>{await 'Nothing'; console.log(x); await new Promise(resolve=>setTimeout(resolve,2000)); console.log(x)})(); x='Received synchronous change'; setTimeout(()=>{x='Received change'},1000)
ele geraReceived synchronous change
eReceived change