Je suis passé en revue async
/ await
et après avoir parcouru plusieurs articles, j'ai décidé de tester les choses moi-même. Cependant, je n'arrive pas à comprendre pourquoi cela ne fonctionne pas:
async function main() {
var value = await Promise.resolve('Hey there');
console.log('inside: ' + value);
return value;
}
var text = main();
console.log('outside: ' + text);
La console génère les éléments suivants (nœud v8.6.0):
> extérieur: [promesse d'objet]
> à l'intérieur: Hé là
Pourquoi le message de journal à l'intérieur de la fonction s'exécute-t-il ensuite? Je pensais que la raison async
/ await
avait été créée était pour effectuer une exécution synchrone à l'aide de tâches asynchrones.
Existe-t-il un moyen d'utiliser la valeur retournée dans la fonction sans utiliser un .then()
après main()
?
await
n'est rien d'autre que du sucre pour lathen
syntaxe de promesse .main
async/await
fait partie de l'ES2017, pas de l'ES7 (ES2016)Réponses:
Parce que
main
renvoie une promesse; toutes lesasync
fonctions le font.Au niveau supérieur, vous devez soit:
Utilisez une
async
fonction de niveau supérieur qui ne rejette jamais (sauf si vous souhaitez des erreurs de «rejet non géré»), ouUtilisez
then
etcatch
, ou(Prochainement!) Utilisez le plus haut niveau
await
, une proposition qui a atteint l'étape 3 dans le processus qui permet une utilisation de haut niveauawait
dans un module.# 1 - De haut niveau
async
Fonction de qui ne rejette jamaisRemarquez le
catch
; vous devez gérer les rejets de promesse / exceptions asynchrones, car rien d'autre ne le fera; vous n'avez aucun appelant à qui les transmettre. Si vous préférez, vous pouvez le faire sur le résultat de son appel via lacatch
fonction (plutôt quetry
/catch
syntax):... ce qui est un peu plus concis (je l'aime pour cette raison).
Ou, bien sûr, ne gérez pas les erreurs et autorisez simplement l'erreur de «rejet non géré».
# 2 -
then
etcatch
Le
catch
gestionnaire sera appelé si des erreurs se produisent dans la chaîne ou dans votrethen
gestionnaire. (Assurez-vous que votrecatch
gestionnaire ne renvoie pas d'erreurs, car rien n'est enregistré pour les gérer.)Ou les deux arguments pour
then
:Notez à nouveau que nous enregistrons un gestionnaire de rejet. Mais sous cette forme, assurez-vous qu'aucun de vos
then
rappels ne renvoie d'erreurs, rien n'est enregistré pour les gérer.# 3 de haut niveau
await
dans un moduleVous ne pouvez pas utiliser
await
au niveau supérieur d'un script non-module, mais la proposition de niveau supérieurawait
( étape 3 ) vous permet de l'utiliser au niveau supérieur d'un module. C'est similaire à l'utilisation d'unasync
wrapper de fonction de niveau supérieur (n ° 1 ci-dessus) en ce sens que vous ne voulez pas que votre code de niveau supérieur rejette (renvoie une erreur) car cela entraînera une erreur de rejet non gérée. Donc, à moins que vous ne souhaitiez avoir ce rejet non géré lorsque les choses tournent mal, comme avec # 1, vous voudrez envelopper votre code dans un gestionnaire d'erreurs:Notez que si vous faites cela, tout module qui importe depuis votre module attendra que la promesse que vous êtes
await
en cours se concrétise; Lorsqu'un module utilisant le niveau supérieurawait
est évalué, il renvoie essentiellement une promesse au chargeur de module (comme le fait uneasync
fonction), qui attend que cette promesse soit réglée avant d'évaluer les corps de tout module qui en dépend.la source
async
/await
sont du sucre syntaxique autour des promesses (le bon type de sucre :-)). Vous ne pensez pas simplement à cela comme à une promesse; c'est effectivement le cas. ( Détails .)async
option tout d' abord. Pour la fonction de niveau supérieur, je peux le voir de toute façon (principalement à cause de deux niveaux d'indentation sur laasync
version).await
proposition de haut niveau a atteint l'étape 3. :-)Top-Level
await
est passé à l'étape 3, donc la réponse à votre question Comment puis-je utiliser async / await au niveau supérieur? consiste simplement à ajouterawait
l'appel àmain()
:Ou juste:
Gardez à l'esprit qu'il est toujours disponible uniquement dans [email protected] .
Si vous utilisez TypeScript , il a atterri en 3.8 .
la v8 a ajouté un support dans les modules.
Il est également soutenu par Deno (comme commenté par gonzalo-bahamondez).
la source
La vraie solution à ce problème est de l'aborder différemment.
Votre objectif est probablement une sorte d'initialisation qui se produit généralement au niveau supérieur d'une application.
La solution consiste à s'assurer qu'il n'y a qu'une seule instruction JavaScript au niveau supérieur de votre application. Si vous n'avez qu'une seule instruction en haut de votre application, alors vous êtes libre d'utiliser async / await à tout autre point n'importe où (sous réserve bien sûr des règles de syntaxe normales)
En d'autres termes, enveloppez tout votre niveau supérieur dans une fonction afin qu'il ne soit plus le niveau supérieur et cela résout la question de savoir comment exécuter async / wait au niveau supérieur d'une application - vous ne le faites pas.
Voici à quoi devrait ressembler le niveau supérieur de votre application:
la source
application()
soit asynchrone?Pour donner plus d'informations en plus des réponses actuelles:
Le contenu d'un
node.js
fichier est actuellement concaténé, à la manière d'une chaîne, pour former un corps de fonction.Par exemple si vous avez un fichier
test.js
:Puis
node.js
concaténera secrètement une fonction qui ressemble à:La principale chose à noter est que la fonction résultante n'est PAS une fonction asynchrone. Vous ne pouvez donc pas utiliser le terme
await
directement à l'intérieur!Mais disons que vous devez travailler avec les promesses de ce fichier, alors il existe deux méthodes possibles:
await
directement dans la fonctionawait
L'option 1 nous oblige à créer une nouvelle portée (et cette portée peut l'être
async
, car nous en avons le contrôle):L'option 2 nous oblige à utiliser l'API de promesse orientée objet (le paradigme moins joli mais tout aussi fonctionnel de travailler avec des promesses)
J'espère personnellement que, si cela fonctionne, node.js concaténera par défaut le code dans une
async
fonction. Cela éliminerait ce mal de tête.la source
L'attente de niveau supérieur est une fonctionnalité du prochain standard EcmaScript. Actuellement, vous pouvez commencer à l'utiliser avec TypeScript 3.8 (en version RC pour le moment).
Comment installer TypeScript 3.8
Vous pouvez commencer à utiliser TypeScript 3.8 en l'installant à partir de npm à l'aide de la commande suivante:
À ce stade, vous devez ajouter la
rc
balise pour installer la dernière version de typescript 3.8.la source
Puisque
main()
s'exécute de manière asynchrone, il renvoie une promesse. Vous devez obtenir le résultat dans lathen()
méthode. Et parce que lesthen()
retours sont prometteurs aussi, vous devez appelerprocess.exit()
pour mettre fin au programme.la source
exit()
pour signaler si une erreur s'est produite.process.exit(1)