TL; DR: Parce que +=
lit x
avant, mais l'écrit après qu'il a changé, en raison du await
mot - clé dans son deuxième opérande (côté droit).
async
les fonctions s'exécutent de manière synchrone lors de leur appel jusqu'à la première await
instruction.
Donc, si vous supprimez await
, il se comporte comme une fonction normale (à l'exception qu'il renvoie toujours une promesse).
Dans ce cas, vous obtenez 5
et 6
dans la console:
let x = 0;
async function test() {
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Le premier await
arrête l'exécution synchrone, même si son argument est disponible de manière synchrone, donc ce qui suit reviendra 1
et 6
, comme vous vous y attendez:
let x = 0;
async function test() {
// Enter asynchrony
await 0;
x += 5;
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Cependant, votre cas est un peu plus compliqué.
Vous avez mis à l' await
intérieur une expression, qui utilise +=
.
Vous savez probablement que JS x += y
est identique à x = (x + y)
. Je vais utiliser ce dernier formulaire pour une meilleure compréhension:
let x = 0;
async function test() {
x = (x + await 5);
console.log('x :', x);
}
test();
x += 1;
console.log('x :', x);
Lorsque l'interprète atteint cette ligne ...
x = (x + await 5);
... il commence à l'évaluer, et il se transforme en ...
x = (0 + await 5);
... puis, il atteint le await
et s'arrête.
Le code après l'appel de fonction commence à s'exécuter et modifie la valeur de x
, puis l'enregistre.
x
est maintenant 1
.
Ensuite, après la fin du script principal, l'interpréteur revient à la test
fonction suspendue et continue d'évaluer cette ligne:
x = (0 + 5);
Et, puisque la valeur de x
est déjà substituée, elle reste 0
.
Enfin, l'interprète fait l'ajout, les magasins 5
à x
, et l' enregistre.
Vous pouvez vérifier ce comportement en vous connectant à l'intérieur d'un getter / setter de propriété d'objet (dans cet exemple, y.z
reflète la valeur de x
:
let x = 0;
const y = {
get z() {
console.log('get x :', x);
return x;
},
set z(value) {
console.log('set x =', value);
x = value;
}
};
async function test() {
console.log('inside async function');
y.z += await 5;
console.log('x :', x);
}
test();
console.log('main script');
y.z += 1;
console.log('x :', x);
/* Output:
inside async function
get x : 0 <-- async fn reads
main script
get x : 0
set x = 1
x : 1
set x = 5 <-- async fn writes
x : 5 <-- async fn logs
*/
/* Just to make console fill the available space */
.as-console-wrapper {
max-height: 100% !important;
}
await (x += 5)
etx += await 5
.