Compte tenu des exemples de code ci-dessous, y a-t-il une différence de comportement et, si oui, quelles sont ces différences?
return await promise
async function delay1Second() {
return (await delay(1000));
}
return promise
async function delay1Second() {
return delay(1000);
}
Si je comprends bien, le premier aurait une gestion des erreurs dans la fonction asynchrone, et les erreurs sortiraient de la promesse de la fonction async. Cependant, la seconde nécessiterait un tick de moins. Est-ce correct?
Cet extrait de code n'est qu'une fonction courante pour renvoyer une promesse à titre de référence.
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
javascript
async-await
PitaJ
la source
la source
async
de votre second (return promise
) échantillon.promise.then(() => nestedPromise)
s'aplatirait et "suivrait" lenestedPromise
. Intéressant à quel point c'est différent des tâches imbriquées dans C # où nous aurions à leUnwrap
faire. D'un autre côté, il semble que celaawait somePromise
appellePromise.resolve(somePromise).then
, plutôt que justesomePromise.then
, avec quelques différences sémantiques intéressantes.Réponses:
La plupart du temps, il n'y a pas de différence observable entre
return
etreturn await
. Les deux versions dedelay1Second
ont exactement le même comportement observable (mais selon l'implémentation, lareturn await
version peut utiliser un peu plus de mémoire car unPromise
objet intermédiaire peut être créé).Cependant, comme @PitaJ l'a souligné, il y a un cas où il y a une différence: si le
return
oureturn await
est imbriqué dans un bloctry
-catch
. Prenons cet exempleDans la première version, la fonction async attend la promesse rejetée avant de renvoyer son résultat, ce qui fait que le rejet est transformé en exception et la
catch
clause est atteinte; la fonction renverra donc une promesse résolvant la chaîne "Saved!".Cependant, la deuxième version de la fonction renvoie la promesse rejetée directement sans l'attendre dans la fonction asynchrone , ce qui signifie que le
catch
cas n'est pas appelé et que l'appelant obtient le rejet à la place.la source
return new Promise(function(resolve, reject) { })
dans unefor...of
boucle, puis l'appelresolve()
dans la boucle après unpipe()
ne suspend pas l'exécution du programme jusqu'à ce que le tuyau soit terminé, comme souhaité, mais l'utilisation leawait new Promise(...)
fait. cette dernière syntaxe est-elle même valide / correcte? est-ce un «raccourci» pourreturn await new Promise(...)
? pourriez-vous m'aider à comprendre pourquoi le second fonctionne et le premier non? pour le contexte, le scénario estsolution 02
de cette réponseComme d'autres réponses l'ont mentionné, il y a probablement un léger avantage en termes de performances à laisser la promesse remonter en la renvoyant directement - simplement parce que vous n'avez pas à attendre le résultat d'abord, puis à l'envelopper à nouveau avec une autre promesse. Cependant, personne n'a encore parlé d' optimisation des appels de fin .
L'optimisation des appels de queue , ou «appels de queue appropriés» , est une technique que l'interpréteur utilise pour optimiser la pile d'appels. Actuellement, peu d'exécutables le prennent encore en charge - même s'il fait techniquement partie de la norme ES6 - mais il est possible qu'un support soit ajouté à l'avenir, vous pouvez donc vous préparer à cela en écrivant un bon code dans le présent.
En un mot, TCO (ou PTC) optimise la pile d'appels en n'ouvrant pas de nouveau cadre pour une fonction qui est directement renvoyée par une autre fonction. Au lieu de cela, il réutilise le même cadre.
Comme
delay()
est directement renvoyé pardelay1Second()
, les environnements d'exécution prenant en charge PTC ouvriront d'abord un cadre pourdelay1Second()
(la fonction externe), mais au lieu d'ouvrir un autre cadre pourdelay()
(la fonction interne), il réutilisera simplement le même cadre qui a été ouvert pour la fonction externe. Cela optimise la pile car cela peut empêcher un débordement de pile (hehe) avec de très grandes fonctions récursives, par exemplefibonacci(5e+25)
. Essentiellement, cela devient une boucle, ce qui est beaucoup plus rapide.PTC n'est activé que lorsque la fonction interne est directement renvoyée. Il n'est pas utilisé lorsque le résultat de la fonction est modifié avant d'être renvoyé, par exemple, si vous aviez
return (delay(1000) || null)
, oureturn await delay(1000)
.Mais comme je l'ai dit, la plupart des environnements d'exécution et des navigateurs ne prennent pas encore en charge PTC, donc cela ne fait probablement pas une énorme différence maintenant, mais cela ne pourrait pas nuire à la pérennité de votre code.
Pour en savoir plus, lisez cette question: Node.js: existe-t-il des optimisations pour les appels de queue dans les fonctions asynchrones?
la source
C'est une question à laquelle il est difficile de répondre, car cela dépend en pratique de la façon dont votre transpilateur
babel
rend (probablement ) réellementasync/await
. Les choses qui sont claires malgré tout:Les deux implémentations doivent se comporter de la même manière, bien que la première implémentation puisse en avoir une de moins
Promise
dans la chaîne.Surtout si vous supprimez ce qui est inutile
await
, la deuxième version ne nécessiterait aucun code supplémentaire de la part du transpilateur, contrairement à la première.Donc, du point de vue des performances du code et du débogage, la deuxième version est préférable, bien que très légèrement, tandis que la première version présente un léger avantage de lisibilité, en ce qu'elle indique clairement qu'elle renvoie une promesse.
la source
undefined
) et le second renvoie aPromise
.async/await
- j'ai beaucoup plus de mal à raisonner. @PitaJ est correct, les deux fonctions renvoient une promesse.try-catch
? Dans lereturn promise
cas, aucunrejection
ne serait attrapé, c'est exact, alors que dans lereturn await promise
cas, ce serait le cas, non?await
chacun d'eux sur un site d'appel, le résultat sera très différent.ici je laisse un peu de code pratique pour que vous puissiez comprendre la différence
la fonction "x" est juste une fonction asynchrone qu'elle n'a d'autre fucn si elle supprimera le retour elle affichera "plus de code ..."
la variable x est juste une fonction asynchrone qui à son tour a une autre fonction asynchrone, dans le principal du code nous invoquons une attente pour appeler la fonction de la variable x, quand elle se termine, elle suit la séquence du code, ce serait normal pour "async / await", mais à l'intérieur de la fonction x il y a une autre fonction asynchrone, et cela retourne une promesse ou retourne une "promesse", il restera à l'intérieur de la fonction x, oubliant le code principal, c'est-à-dire qu'il n'imprimera pas le "console.log (" plus de code .. "), par contre si nous mettons" wait "il attendra chaque fonction qui se termine et suivra finalement la séquence normale du code principal.
sous le "console.log (" terminé 1 "supprimez le" retour ", vous verrez le comportement.
la source
Voici un exemple dactylographié que vous pouvez exécuter et vous convaincre que vous avez besoin de ce "retour en attente"
la source
Différence notable: le rejet de promesses est traité à différents endroits
return somePromise
passera somePromise au site d'appel, etawait
somePromise à régler sur le site d'appel (s'il y en a). Par conséquent, si somePromise est rejeté, il ne sera pas géré par le bloc catch local, mais par le bloc catch du site d'appel.return await somePromise
attendra d'abord une promesse de s'installer localement. Par conséquent, la valeur ou l'exception sera d'abord traitée localement. => Le bloc catch local sera exécuté s'ilsomePromise
est rejeté.Raison:
return await Promise
attend à la fois localement et à l'extérieur,return Promise
n'attend qu'à l'extérieurÉtapes détaillées:
promesse de retour
delay1Second()
;delay1Second()
, la fonctiondelay(1000)
renvoie immédiatement une promesse avec[[PromiseStatus]]: 'pending
. Appelons çadelayPromise
.Promise.resolve()
( Source ). Parce quedelay1Second
c'est une fonction asynchrone, nous avons:Promise.resolve(delayPromise)
renvoiedelayPromise
sans rien faire car l'entrée est déjà une promesse (voir MDN Promise.resolve ):await
attend que ledelayPromise
soit réglé.delayPromise
est rempli avec PromiseValue = 1:delayPromise
est rejeté:retour attendre promesse
delay1Second()
;delay1Second()
, la fonctiondelay(1000)
renvoie immédiatement une promesse avec[[PromiseStatus]]: 'pending
. Appelons çadelayPromise
.delayPromise
être réglée.delayPromise
est rempli avec PromiseValue = 1:delayPromise
est rejeté:Glossaire:
Promise.[[PromiseStatus]]
passe depending
àresolved
ourejected
la source