J'ai lu que les fonctions asynchrones marquées par le mot clé async
renvoient implicitement une promesse:
async function getVal(){
return await doSomethingAync();
}
var ret = getVal();
console.log(ret);
mais ce n'est pas cohérent ... en supposant que doSomethingAsync()
renvoie une promesse, et le mot-clé wait retournera la valeur de la promesse, pas la promesse itsef, alors ma fonction getVal devrait return cette valeur, pas une promesse implicite.
Alors, quel est exactement le cas? Les fonctions marquées par le mot clé async renvoient-elles implicitement les promesses ou contrôlons-nous ce qu'elles renvoient?
Peut-être que si nous ne retournons pas explicitement quelque chose, ils renvoient implicitement une promesse ...?
Pour être plus clair, il y a une différence entre ce qui précède et
function doSomethingAync(charlie) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(charlie || 'yikes');
}, 100);
})
}
async function getVal(){
var val = await doSomethingAync(); // val is not a promise
console.log(val); // logs 'yikes' or whatever
return val; // but this returns a promise
}
var ret = getVal();
console.log(ret); //logs a promise
Dans mon résumé, le comportement est en effet incompatible avec les instructions de retour traditionnelles. Il semble que lorsque vous renvoyez explicitement une valeur non-promise d'une fonction async
, il sera forcé de l'envelopper dans une promesse. Je n'ai pas de gros problème avec ça, mais ça défie JS normal.
La valeur de retour sera toujours une promesse. Si vous ne retournez pas explicitement une promesse, la valeur que vous retournez sera automatiquement encapsulée dans une promesse.
async function increment(num) {
return num + 1;
}
// Even though you returned a number, the value is
// automatically wrapped in a promise, so we call
// `then` on it to access the returned value.
//
// Logs: 4
increment(3).then(num => console.log(num));
Même chose même s'il y a un await
.
function defer(callback) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(callback());
}, 1000);
});
}
async function incrementTwice(num) {
const numPlus1 = await defer(() => num + 1);
return numPlus1 + 1;
}
// Logs: 5
incrementTwice(3).then(num => console.log(num));
Les promesses se déroulent automatiquement. Ainsi, si vous retournez une promesse pour une valeur à partir d'une fonction async
, vous recevrez une promesse pour la valeur (et non une promesse d'une promesse pour la valeur).
function defer(callback) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(callback());
}, 1000);
});
}
async function increment(num) {
// It doesn't matter whether you put an `await` here.
return defer(() => num + 1);
}
// Logs: 4
increment(3).then(num => console.log(num));
Dans mon résumé, le comportement est en effet incompatible avec les instructions de retour traditionnelles. Il semble que lorsque vous renvoyez explicitement une valeur non-promise d'une fonction asynchrone, il sera forcé de l'envelopper dans une promesse. Je n'ai pas de gros problème avec ça, mais ça défie JS normal.
ES6 a des fonctions qui ne renvoient pas exactement la même valeur que return
. Ces fonctions sont appelées générateurs.
function* foo() {
return 'test';
}
// Logs an object.
console.log(foo());
// Logs 'test'.
console.log(foo().next().value);
J'ai jeté un coup d'oeil à la spécification et trouvé les informations suivantes. La version courte est qu'un async function
desugars à un générateur qui donne Promise
s. Donc, oui, les fonctions asynchrones renvoient des promesses .
Selon tc39 spec , ce qui suit est vrai:
async function <name>?<argumentlist><body>
Desugars to:
function <name>?<argumentlist>{ return spawn(function*() <body>, this); }
Où spawn
"est un appel à l'algorithme suivant":
function spawn(genF, self) {
return new Promise(function(resolve, reject) {
var gen = genF.call(self);
function step(nextF) {
var next;
try {
next = nextF();
} catch(e) {
// finished with failure, reject the promise
reject(e);
return;
}
if(next.done) {
// finished with success, resolve the promise
resolve(next.value);
return;
}
// not finished, chain off the yielded promise and `step` again
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}