343 votes

Comment utiliser async / wait au plus haut niveau?

J'ai été sur async/await et après être passé dans plusieurs articles, j'ai décidé de tester des choses moi-même. Cependant, je n'arrive pas à envelopper ma tête autour de 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 résultats suivants (nœud v8.6.0) :

> extérieur: [objet de la Promesse]

> à l'intérieur: Hé là

Pourquoi le message de journal à l'intérieur de la fonction à exécuter par la suite? Je pensais que la raison async/await a été créé dans le but d'effectuer l'exécution synchrone à l'aide de tâches asynchrones.

Est-il un moyen que je pourrais utiliser la valeur retournée à l'intérieur de la fonction, sans l'aide d'un .then() après main()?

449voto

T.J. Crowder Points 285826

Je n'arrive pas à envelopper ma tête autour de pourquoi cela ne fonctionne pas.

Parce qu' main retourne une promesse; tous async fonctions ne.

Au niveau supérieur, vous devez:

  1. Utilisation de haut niveau- async fonction qui ne rejette (sauf si vous voulez "non gérée rejet" des erreurs), ou

  2. Utiliser then et catch, ou

  3. (À venir bientôt!) Utilisation de haut-niveau await, une proposition qui a atteint l'Étape 3 dans le processus qui permet aux haut-niveau de l'utilisation de await dans un module.

#1 - Haut niveau- async fonction qui ne rejette

(async () => {
    try {
        var text = await main();
        console.log(text);
    } catch (e) {
        // Deal with the fact the chain failed
    }
})();

Avis de l' catch; vous devez gérer promesse rejets / async des exceptions, puisque rien d'autre ne va; vous n'avez pas à l'appelant de les transmettre. Si vous préférez, vous pouvez le faire sur le résultat de l'appel par l'intermédiaire de l' catch de la fonction (plutôt que d' try/catch de la syntaxe):

(async () => {
    var text = await main();
    console.log(text);
})().catch(e => {
    // Deal with the fact the chain failed
});

...qui est un peu plus concis (je l'aime pour cette raison).

Ou, bien sûr, ne gère pas les erreurs et permettre aux "non gérée rejet d'erreur".

#2 - then et catch

main()
    .then(text => {
        console.log(text);
    })
    .catch(err => {
        // Deal with the fact the chain failed
    });

L' catch gestionnaire sera appelé si des erreurs se produisent dans la chaîne ou dans votre then gestionnaire. (Assurez-vous que votre catch gestionnaire ne jetez pas les erreurs, comme rien n'est enregistré pour les gérer.)

Ou les deux arguments au then:

main().then(
    text => {
        console.log(text);
    },
    err => {
        // Deal with the fact the chain failed
    }
);

Notez une fois de plus nous sommes à l'enregistrement d'un rejet de gestionnaire. Mais dans ce formulaire, assurez-vous qu'aucun de vos then rappels ne jette pas des erreurs, rien n'est enregistré pour les gérer.

#3 top-niveau await dans un module

Vous ne pouvez pas utiliser await au plus haut niveau de non-module de script, mais le haut niveau de l' await proposition (Étape 3) vous permet de l'utiliser au plus haut niveau d'un module. Il est similaire à l'utilisation d'un haut-niveau de l' async fonction wrapper (#1 ci-dessus) que vous ne voulez pas que votre haut niveau code à rejeter (jeter une erreur) parce que cela va entraîner un non gérée rejet d'erreur. Donc, sauf si vous voulez que non gérée rejet quand les choses vont mal, comme avec n ° 1, vous souhaitez envelopper votre code dans un gestionnaire d'erreur:

// In a module, once the top-level `await` proposal lands
try {
    var text = await main();
    console.log(text);
} catch (e) {
    // Deal with the fact the chain failed
}

27voto

lautaro.dragan Points 337

Niveau supérieur await a été déplacé à l'étape 3, si la réponse à votre question Comment puis-je utiliser async/await au haut niveau? est juste d'ajouter await l'appel à main() :

async function main() {  
    var value = await Promise.resolve('Hey there');
    console.log('inside: ' + value);
    return value;
}

var text = await main();  
console.log('outside: ' + text)

Ou tout simplement:

const text = await Promise.resolve('Hey there');
console.log('outside: ' + text)

Ne gardez à l'esprit qu'il est toujours disponible uniquement dans Webpack@v5.0.0-alpha.15.

12voto

Gershom Maes Points 208

Pour apporter un complément d'info sur le dessus de l'actuel réponses:

Le contenu d'un node.js le fichier sont actuellement concaténés, dans une chaîne de façon semblable, pour la forme du corps d'une fonction.

Par exemple, si vous avez un fichier test.js:

// Amazing test file!
console.log('Test!');

Ensuite, node.js secrètement concaténer une fonction qui ressemble à ceci:

function(require, __dirname, ... a bunch more top-level properties) {
  // Amazing test file!
  console.log('test!');
}

La chose importante à noter est que la fonction n'est PAS une fonction async. Si vous ne pouvez pas utiliser le terme await directement à l'intérieur de celui-ci!

Mais dire que vous avez besoin de travailler avec des promesses dans ce fichier, alors il y a deux méthodes possibles:

  1. Ne pas utiliser await directement à l'intérieur de la fonction
  2. Ne pas utiliser await

Option 1 nous oblige à créer un nouveau champ d'application (et de CETTE portée peut être async, parce que nous avons le contrôle sur elle):

// Amazing test file!
// Create a new async function (a new scope) and immediately call it!
(async () => {
  await new Promise(...);
  console.log('Test!');
})();

Option 2 nous oblige à utiliser orientée objet, la promesse de l'API (le moins joli mais tout aussi fonctionnelle paradigme de travailler avec des promesses)

// Amazing test file!
// Create some sort of promise...
let myPromise = new Promise(...);

// Now use the object-oriented API
myPromise.then(() => console.log('Test!'));

J'espère personnellement que, si c'est réalisable, node.js par défaut, concaténer code en async fonction. Qui pourrait se débarrasser de ce mal de tête.

5voto

Duke Dougal Points 932

La véritable solution à ce problème consiste à l'aborder différemment.

Probablement votre objectif est une sorte de l'initialisation, qui arrive généralement au plus haut niveau d'une application.

La solution est de s'assurer qu'il n'y a qu'un seul JavaScript déclaration au plus haut niveau de votre application. Si vous avez une seule instruction dans la partie supérieure de votre application, puis vous êtes libre de les utiliser async/await à tous les autres points partout (sous réserve bien sûr à la normale des règles de syntaxe)

Mettre une autre manière, envelopper la totalité de votre haut niveau dans une fonction de sorte qu'il n'est plus le haut niveau et qui résout la question de la façon d'exécuter async/await au plus haut niveau de l'application, vous n'avez pas.

C'est ce que le haut niveau de votre application devrait ressembler à:

import {application} from './server'

application();

-7voto

Peracek Points 453

Étant donné que main() s'exécute de manière asynchrone, une promesse est retournée. Vous devez obtenir le résultat avec la méthode then() . Et comme then() retours sont promis, vous devez appeler process.exit() pour terminer le programme.

 main()
   .then(
      (text) => { console.log('outside: ' + text) },
      (err)  => { console.log(err) }
   )
   .then(() => { process.exit() } )
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X