wait n'est valide que dans la fonction async


130

J'ai écrit ce code en lib/helper.js

var myfunction = async function(x,y) {
   ....
   reutrn [variableA, variableB]
}
exports.myfunction = myfunction;

puis j'ai essayé de l'utiliser dans un autre fichier

 var helper = require('./helper.js');   
 var start = function(a,b){
     ....
     const result = await helper.myfunction('test','test');
 }
 exports.start = start;

J'ai une erreur

"wait n'est valide que dans la fonction async"

Quelle est la solution?


1
Eh bien, le problème est que awaitcela ne peut être utilisé que dans une asyncfonction. Autrement dit, awaitrend une fonction asynchrone, elle doit donc être déclarée comme telle.
Pointy

Quelle est l'erreur actuelle?
acdcjunior

toujours le même, SyntaxError: await n'est valide que dans la fonction async
j.doe

Vous devez partager plus de contexte sur votre code.
Ele

Réponses:


160

L'erreur ne se réfère pas à myfunctionmais à start.

async function start() {
   ....

   const result = await helper.myfunction('test', 'test');
}

// My function
const myfunction = async function(x, y) {
  return [
    x,
    y,
  ];
}

// Start function
const start = async function(a, b) {
  const result = await myfunction('test', 'test');
  
  console.log(result);
}

// Call start
start();



J'utilise l'occasion de cette question pour vous conseiller sur un modèle connu en utilisant contre ce awaitqui est: return await.


FAUX

async function myfunction() {
  console.log('Inside of myfunction');
}

// Here we wait for the myfunction to finish
// and then returns a promise that'll be waited for aswell
// It's useless to wait the myfunction to finish before to return
// we can simply returns a promise that will be resolved later

// useless async here
async function start() {
  // useless await here
  return await myfunction();
}

// Call start
(async() => {
  console.log('before start');

  await start();
  
  console.log('after start');
})();


CORRECT

async function myfunction() {
  console.log('Inside of myfunction');
}

// Here we wait for the myfunction to finish
// and then returns a promise that'll be waited for aswell
// It's useless to wait the myfunction to finish before to return
// we can simply returns a promise that will be resolved later

// Also point that we don't use async keyword on the function because
// we can simply returns the promise returned by myfunction
function start() {
  return myfunction();
}

// Call start
(async() => {
  console.log('before start');

  await start();
  
  console.log('after start');
})();


Sachez également qu'il existe un cas particulier où return awaitest correct et important: (en utilisant try / catch)

Y a-t-il des problèmes de performances avec «return await»?


Mais cela ne fonctionne pas, j'ai mis à jour mon code. Je reçois toujours la même erreur
j.doe

@ j.doe J'ai ajouté un extrait
Grégory NEUT

2
Merci, j'ai trouvé mon problème. J'essayais de le faire à l'intérieur d'un rappel est la fonction start (). La solution était: const start = fonction asynchrone (a, b) {task.get (options, fonction asynchrone (erreur, résultat1) {const résultat = attendre mafonction ('test', 'test');
j.doe

Considérant que Node est un seul thread. Cela ne réduit-il pas la demande par minutes et augmente également le délai entre les demandes de remplissage complet.
Rishabh Dhiman

1
Il convient de mentionner que dans l'exemple "CORRECT", il n'est pas nécessaire de déclarer en starttant que asyncfonction (bien que certains choisissent de le faire de toute façon, afin d'être plus explicite)
Gershom

11

Quand j'ai eu cette erreur, il s'est avéré que j'avais un appel à la fonction de carte dans ma fonction "async", donc ce message d'erreur faisait en fait référence à la fonction de carte qui n'était pas marquée comme "async". J'ai contourné ce problème en retirant l'appel "await" de la fonction de carte et en proposant un autre moyen d'obtenir le comportement attendu.

var myfunction = async function(x,y) {
    ....
    someArray.map(someVariable => { // <- This was the function giving the error
        return await someFunction(someVariable);
    });
}

2
C'était le problème pour moi. J'ai remplacé la fonction map par une boucle for, ce qui était une solution simple pour moi. Cependant, cette solution peut ne pas fonctionner pour vous en fonction de votre code.
Thomas

6
FYI you can also dosomeArray.map(async (someVariable) => { return await someFunction(someVariable)})
ptim

1
Le awaitdans votre code est trompeur, car Array.mapne gérera pas la fonction comme une fonction asynchrone. Pour être parfaitement clair, une fois la mapfonction terminée, le someFunctionsera tout en attente. Si vous voulez vraiment attendre la fin des fonctions, vous devez écrire: await Promise.all(someArray.map(someVariable => someFunction(someVariable)))ou await Promise.all(someArray.map(someFunction))).
Grégory NEUT le

9

Pour l'utiliser await, son contexte d'exécution doit être asyncdans la nature

Comme il l'a dit, vous devez avant tout définir la nature de votre situation executing contextoù vous êtes prêt à effectuer awaitune tâche.

Mettez juste asyncavant la fndéclaration dans laquelle votre asynctâche s'exécutera.

var start = async function(a, b) { 
  // Your async task will execute with await
  await foo()
  console.log('I will execute after foo get either resolved/rejected')
}

Explication:

Dans votre question, vous importez un methodqui est asynchronousdans la nature et s'exécutera en parallèle. Mais là où vous essayez d'exécuter cette asyncméthode, c'est à l'intérieur d'un autre execution contextque vous devez définir asyncpour l'utiliser await.

 var helper = require('./helper.js');   
 var start = async function(a,b){
     ....
     const result = await helper.myfunction('test','test');
 }
 exports.start = start;

Je me demande ce qui se passe sous le capot

awaitconsomme des méthodes / fonctions promises / futures / de retour de tâches et asyncmarque une méthode / fonction comme capable d'utiliser await.

Aussi, si vous êtes familier avec promises, awaitfait en fait le même processus de promesse / résolution. Créer une chaîne de promesse et exécuter votre prochaine tâche en resolverappel.

Pour plus d'informations, vous pouvez vous référer à MDN DOCS .


Même avec async dans la fonction de démarrage
j'obtiens

Je ne sais pas où vous manquez et obtenez cette erreur, il n'y a pas d'explication aussi complexe pour résoudre cette erreur.
Satyam Pathak

c'est une bonne réponse et en fait expliqué la raison soulignée. voté.
linehrr

3

L'implémentation actuelle de async/ awaitne prend en charge que le awaitmot - clé à l'intérieur des asyncfonctions. Modifiez la startsignature de votre fonction pour pouvoir l'utiliser à l' awaitintérieur start.

 var start = async function(a, b) {

 }

Pour les personnes intéressées, la proposition de top-level awaitest actuellement à l'étape 2: https://github.com/tc39/proposal-top-level-await


1
Malheureusement, cela signifie essentiellement que vous allez devoir rendre TOUTES vos fonctions asynchrones, sur toute votre base de code. Parce que si vous voulez utiliser await, vous devez le faire dans une fonction asynchrone, ce qui signifie que vous devez attendre la réponse de cette fonction dans la fonction qui l'appelle - encore une fois, cela signifie que TOUTES vos fonctions devront devenir asynchrones. Pour moi, cela signifie qu'attendre async n'est pas prêt à être utilisé. Lorsque vous pouvez utiliser await pour appeler une méthode asynchrone, que la fonction actuelle soit synchrone ou asynchrone, elle sera prête pour les heures de grande écoute.
Rodney P. Barbati le

1
Chaque fonction qui passe par n'importe quel niveau d'indirection dépendant des résultats d'un processus externe doit, et doit être définie avec async- c'est tout l'intérêt de async.
Gershom le

Vous pouvez actuellement l'utiliser dans le nœud repl en utilisant l' --experimental-repl-awaitoption.
lodz

3

J'ai eu le même problème et le bloc de code suivant donnait le même message d'erreur:

repositories.forEach( repo => {
        const commits = await getCommits(repo);
        displayCommit(commits);
});

Le problème est que la méthode getCommits () était asynchrone mais je lui passais l'argument repo qui était également produit par une promesse. Donc, j'ai dû ajouter le mot async comme ceci: async (repo) et cela a commencé à fonctionner:

repositories.forEach( async(repo) => {
        const commits = await getCommits(repo);
        displayCommit(commits);
});

0

async / await est le mécanisme de gestion de la promesse, deux façons de le faire

functionWhichReturnsPromise()
            .then(result => {
                console.log(result);
            })
            .cathc(err => {
                console.log(result);

            });

ou nous pouvons utiliser await pour attendre la promesse de la remplir en premier, ce qui signifie qu'elle est rejetée ou résolue.

Maintenant, si nous voulons utiliser await (en attente d'une promesse à remplir) à l'intérieur d'une fonction, il est obligatoire que la fonction conteneur soit une fonction asynchrone car nous attendons qu'une promesse se réalise de manière asynchrone || fait sens non ?.

async function getRecipesAw(){
            const IDs = await getIds; // returns promise
            const recipe = await getRecipe(IDs[2]); // returns promise
            return recipe; // returning a promise
        }

        getRecipesAw().then(result=>{
            console.log(result);
        }).catch(error=>{
            console.log(error);
        });

-2

"wait n'est valide que dans la fonction async"

Mais pourquoi? 'wait' transforme explicitement un appel asynchrone en appel synchrone, et par conséquent l'appelant ne peut pas être asynchrone (ou asyncable) - du moins, pas à cause de l'appel effectué à 'wait'.


1
En fait, attendre n'attend pas les résultats - il renvoie immédiatement une promesse. C'est exactement ce que j'essayais de transmettre. Si wait attendait réellement et ne renvoyait pas le contrôle à l'appelant, alors toute fonction contenant un mot-clé await ne pourrait littéralement pas être marquée comme asynchrone. Mais au lieu de cela, nous avons toute fonction qui contient wait ou appelle une fonction qui appelle finalement une fonction contenant wait doit être asynchrone. Fondamentalement, si vous appelez wait ne serait-ce qu'une seule fois, toutes vos fonctions doivent être marquées comme asynchrones.
Rodney P. Barbati

-5

Oui, attendre / async était un excellent concept, mais l'implémentation est complètement cassée.

Pour une raison quelconque, le mot-clé await a été implémenté de telle sorte qu'il ne peut être utilisé que dans une méthode async. Il s'agit en fait d'un bogue, même si vous ne le verrez pas désigné comme tel ailleurs que ici. Le correctif de ce bogue serait d'implémenter le mot-clé await de sorte qu'il ne puisse être utilisé que POUR APPELER une fonction asynchrone, que la fonction appelante soit elle-même synchrone ou asynchrone.

En raison de ce bogue, si vous utilisez await pour appeler une fonction asynchrone réelle quelque part dans votre code, alors TOUTES vos fonctions doivent être marquées comme asynchrones et TOUS vos appels de fonction doivent utiliser await.

Cela signifie essentiellement que vous devez ajouter la surcharge des promesses à toutes les fonctions de l'ensemble de votre application, dont la plupart ne sont pas et ne seront jamais asynchrones.

Si vous y réfléchissez réellement, l'utilisation de await dans une fonction devrait nécessiter que la fonction contenant le mot-clé await NE SOIT PAS ASYNC - c'est parce que le mot-clé await va interrompre le traitement dans la fonction où se trouve le mot-clé await. Si le traitement dans cette fonction est interrompu, alors il n'est certainement PAS asynchrone.

Donc, aux développeurs de javascript et d'ECMAScript - veuillez corriger l'implémentation d'attente / async comme suit ...

  • wait ne peut être utilisé que pour appeler des fonctions asynchrones.
  • Wait peut apparaître dans n'importe quel type de fonction, synchrone ou asynchrone.
  • Modifiez le message d'erreur de "Wait est uniquement valide dans la fonction asynchrone" à "Wait peut uniquement être utilisé pour appeler des fonctions asynchrones".

Vous pouvez appeler cela un bug si vous le souhaitez, mais je ne suis pas d'accord. Il n'y a pas de code qui "met en pause" - il y a plutôt du code qui ne peut pas se terminer sans les résultats d'un processus externe (généralement io). Un tel code doit être appelé "asynchrone" car de nombreux processus externes doivent pouvoir s'exécuter en même temps (de manière non synchrone), contrairement à la VM javascript qui est monothread. Si vous avez de nombreuses fonctions qui doivent être refactorisées, asynccela reflète le fait que beaucoup de vos fonctions nécessitent les résultats de processus externes. C'est tout à fait canonique à mon avis.
Gershom le

Il convient également de mentionner un terrible inconvénient de limiter awaità n'être utilisable qu'avec des appels de fonction: pour un seul processus externe, un seul point dans le code javascript pourrait être notifié lorsque ce processus se termine. Par exemple, si le contenu d'un fichier est nécessaire à 3 fins indépendantes, chaque objectif devrait le faire indépendamment let content = await readTheFile();- c'est parce que la "promesse du contenu du fichier" ne peut pas être attendue, seulement "l'acte de lire le fichier et de reprendre une fois qu'il a été lis".
Gershom le

Ok, ne l'appelons pas code qui s'arrête, ou code qui ne peut pas se terminer, mais que diriez-vous de l'attente bloquée. Voici le hic - la fonction qui est bloquée en attente ou qui ne peut pas se terminer est la fonction qui contient le mot-clé await. Ce n'est pas la fonction async qui est appelée avec le mot clé await. Par conséquent, la fonction contenant le mot clé await ne devrait certainement PAS être marquée comme asynchrone - elle est bloquée en attente, ce qui est le contraire de asynchrone.
Rodney P. Barbati le

Pour rendre cela parfaitement clair, considérez ce qui suit - await est destiné à simplifier l'utilisation des fonctions asynchrones en les faisant apparaître comme synchrones (c'est-à-dire qu'il me permet de faire les choses dans un ordre spécifique). Forcer la fonction contenant l'attente à être asynchrone est un abus de langage complet - vous avez utilisé wait pour qu'il devienne synchrone. Une fonction contenant un await est absolument, de toutes les manières imaginables, PAS une fonction asynchrone !!!
Rodney P. Barbati le

1
@Gershom - cela semble raisonnable. Merci!
Rodney P. Barbati
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.