web-dev-qa-db-fra.com

Utilisation de wait en dehors d'une fonction asynchrone

J'essayais de chaîner deux fonctions asynchrones ensemble, car la première avait un paramètre de retour conditionnel qui entraînait l'exécution ou la sortie de la seconde du module. Cependant, j'ai trouvé un comportement étrange que je ne trouve pas dans les spécifications.

async function isInLobby() {
    //promise.all([chained methods here])
    let exit = false;
    if (someCondition) exit = true;
}

Ceci est un extrait bâtard de mon code (vous pouvez voir la portée complète ici ), qui vérifie simplement si un joueur est déjà dans un lobby, mais ce n'est pas pertinent.

Ensuite, nous avons cette fonction asynchrone.

async function countPlayer() {
    const keyLength = await scardAsync(game);
    return keyLength;
}

Cette fonction n'a pas besoin de s'exécuter si exit === true.

J'ai essayé de faire

const inLobby = await isInLobby();

J'espérais que cela attendrait les résultats, donc je pourrais utiliser inLobby pour exécuter conditionnellement countPlayer, mais j'ai reçu une erreur de type sans détails spécifiques.

Pourquoi vous ne pouvez pas await un async fonctionner en dehors de la portée de la fonction? Je sais que c’est une promesse en sucre. Il faut donc enchaîner then mais pourquoi est-ce qu’en countPlayer je peux attendre une autre promesse, mais à l’extérieur, je ne peux pas awaitisInLobby?

50
Sterling Archer

Niveau supérieur await n'est pas pris en charge. Le comité de normalisation a discuté de la raison pour laquelle il s'agit, par exemple cette question de Github .

Il y a aussi un réflexion sur Github pourquoi l'attente au plus haut niveau est une mauvaise idée. Plus précisément, il suggère que si vous avez un code comme celui-ci:

// data.js
const data = await fetch( '/data.json' );
export default data;

Maintenant , aucun fichier qui importe data.js ne sera exécuté avant la fin de la récupération, de sorte que tout le chargement de votre module est maintenant bloqué. Il est donc très difficile de raisonner sur l'ordre des modules de l'application, car nous sommes habitués à exécuter Javascript au plus haut niveau de manière synchrone et prévisible. Si cela était autorisé, il est difficile de savoir quand une fonction est définie.

Mon point de vue est que c’est une mauvaise pratique pour votre module d’avoir des effets secondaires simplement en le chargeant. Cela signifie que tout consommateur de votre module aura des effets secondaires simplement en exigeant votre module. Ceci limite mal l’utilisation de votre module. Un niveau supérieur await signifie probablement que vous lisez une API ou appelez un service au moment du chargement . Au lieu de cela, vous devez simplement exporter async. fonctions que les consommateurs peuvent utiliser à leur rythme.

50
Andy Ray

Il y a toujours ceci bien sûr:

(async () => {
    await ...
})();

Cela fait une fonction rapide avec async où vous pouvez utiliser attendre. Cela vous évite d'avoir à créer une fonction asynchrone, ce qui est génial! // crédits Silve2611

72

Encore mieux, mettez un point-virgule supplémentaire devant le bloc de code

;(async () => {
    await ...
})();

Cela empêche le formateur automatique (par exemple, en vscode) de déplacer la première parenthèse à la fin de la ligne précédente.

Le problème peut être démontré sur l'exemple suivant:

const add = x => y => x+y
const increment = add(1)
(async () => {
    await ...
})();

Sans le point-virgule, cela sera reformaté comme suit:

const add = x => y => x+y
const increment = add(1)(async () => {
  await Promise(1)
})()

ce qui est évidemment faux, car il attribue la fonction asynchrone au paramètre y et tente d'appeler une fonction à partir du résultat (qui est en fait une chaîne bizarre '1async () => {...}')

3
Viliam Simko