await è valido solo nella funzione async


130

Ho scritto questo codice in formato lib/helper.js

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

e poi ho provato a usarlo in un altro file

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

Ho ricevuto un errore

"await è valido solo nella funzione async"

Qual'è il problema?


1
Bene, il problema è che awaitpuò essere utilizzato solo all'interno di una asyncfunzione. Cioè, awaitrende una funzione asincrona, quindi deve essere dichiarata come tale.
Pointy

Qual è l'errore attuale?
acdcjunior

sempre lo stesso, SyntaxError: await è valido solo nella funzione async
j.doe

Devi condividere più contesto sul tuo codice.
Ele

Risposte:


160

L'errore non si riferisce a myfunctionma a 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();



Io uso l'occasione di questa domanda per consigliarvi su un noto modello anti usando awaitche è: return await.


SBAGLIATO

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');
})();


CORRETTA

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');
})();


Inoltre, sappi che c'è un caso speciale in cui return awaitè corretto e importante: (usando try / catch)

Ci sono problemi di prestazioni con "return await"?


Ma questo non funziona, ho aggiornato il mio codice. Ricevo ancora lo stesso errore
j.doe

@ j.doe ho aggiunto uno snippet
Grégory NEUT

2
Grazie, ho trovato il mio problema. Stavo cercando di farlo all'interno di un callback è la funzione start (). La soluzione era: const start = async function (a, b) {task.get (options, async function (error, result1) {const result = await myfunction ('test', 'test');
j.doe

Considerando che Node è un singolo thread. Non diminuisce la richiesta al minuto e aumenta anche il ritardo tra le richieste di completamento.
Rishabh Dhiman

1
Vale la pena ricordare che nell'esempio "CORRETTO" non è necessario dichiarare startcome asyncfunzione (anche se alcuni sceglieranno di farlo comunque, per essere più espliciti)
Gershom

11

Quando ho ricevuto questo errore, si è scoperto che avevo una chiamata alla funzione map all'interno della mia funzione "async", quindi questo messaggio di errore si riferiva effettivamente alla funzione map non contrassegnata come "async". Ho aggirato questo problema eliminando la chiamata "await" dalla funzione map e trovando un altro modo per ottenere il comportamento previsto.

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

2
Questo era il problema per me. Ho sostituito la funzione map con un ciclo for, che è stata una soluzione facile per me. Tuttavia, questa soluzione potrebbe non funzionare per te a seconda del tuo codice.
Thomas

6
Cordiali saluti, puoi anche farlosomeArray.map(async (someVariable) => { return await someFunction(someVariable)})
ptim

1
Il awaitnel tuo codice è fuorviante, perché Array.mapnon gestirà la funzione come una funzione asincrona. Per essere perfettamente chiari, una volta terminata la mapfunzione, someFunctionsarà tutto in sospeso. Se vuoi davvero aspettare che le funzioni finiscano devi scrivere: await Promise.all(someArray.map(someVariable => someFunction(someVariable)))o await Promise.all(someArray.map(someFunction))).
Grégory NEUT

9

Per essere utilizzato await, il contesto di esecuzione deve essere asyncnella natura

Come detto, devi definire la natura del tuo luogo in executing contextcui sei disposto a awaitsvolgere un compito prima di ogni altra cosa.

Basta mettere asyncprima della fndichiarazione in cui asyncverrà eseguita l'attività.

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')
}

Spiegazione:

Nella tua domanda, stai importando un methodche è asynchronousin natura e verrà eseguito in parallelo. Ma dove stai cercando di eseguire quel asyncmetodo è all'interno di un diverso execution contextche devi definire asyncper usare await.

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

Chiedendosi cosa sta succedendo sotto il cofano

awaitconsuma metodi / funzioni di ritorno di promesse / futuro / attività e asynccontrassegna un metodo / funzione come in grado di utilizzare await.

Inoltre, se hai familiarità promises, awaitsta effettivamente facendo lo stesso processo di promessa / risoluzione. Crea una catena di promesse e ti esegue il prossimo compito in resolvecallback.

Per maggiori informazioni puoi fare riferimento a MDN DOCS .


Anche con async nella funzione di avvio ricevo l'errore
j.doe

Non sono sicuro di dove ti manchi e di ottenere questo errore, non esiste una spiegazione così complessa per risolvere questo errore.
Satyam Pathak

questa è una risposta corretta e ha effettivamente spiegato il motivo sottolineato. votato.
linehrr

3

L'attuale implementazione di async/ awaitsupporta solo la awaitparola chiave inside of asyncfunctions Cambia la startfirma della tua funzione in modo da poterla usare awaitinside start.

 var start = async function(a, b) {

 }

Per chi fosse interessato, la proposta di primo livello awaitè attualmente in fase 2: https://github.com/tc39/proposal-top-level-await


1
Sfortunatamente, ciò che significa fondamentalmente è che dovrai rendere tutte le tue funzioni asincrone, nell'intera base di codice. Perché se vuoi usare await, devi farlo in una funzione asincrona, il che significa che devi attendere la risposta di quella funzione nella funzione che la chiama - di nuovo, significa che TUTTE le tue funzioni dovranno diventare asincrone. Per me questo significa che await async non è pronto per l'uso. Quando puoi usare await per chiamare un metodo asincrono, indipendentemente dal fatto che la funzione corrente sia sincrona o asincrona, sarà pronta per la prima serata.
Rodney P. Barbati

1
Ogni funzione che dipende dai risultati di un processo esterno attraverso qualsiasi livello di riferimento indiretto deve e deve essere definita con async- questo è l' intero punto di async.
Gershom

Attualmente puoi usarlo in sostituzione del nodo usando l' --experimental-repl-awaitopzione.
lodz

3

Ho avuto lo stesso problema e il seguente blocco di codice dava lo stesso messaggio di errore:

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

Il problema è che il metodo getCommits () era asincrono ma gli stavo passando l'argomento repo che è stato anche prodotto da Promise. Quindi, ho dovuto aggiungere la parola async in questo modo: async (repo) e ha iniziato a funzionare:

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

0

async / await è il meccanismo di gestione della promessa, due modi in cui possiamo farlo

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

            });

oppure possiamo usare await per attendere che la promessa venga compilata per prima, il che significa che viene rifiutata o risolta.

Ora, se vogliamo usare await (in attesa che una promessa venga mantenuta) all'interno di una funzione, è obbligatorio che la funzione contenitore sia una funzione asincrona perché stiamo aspettando che una promessa venga soddisfatta in modo asincrono || ha senso vero ?.

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

"await è valido solo nella funzione async"

Ma perché? "await" trasforma esplicitamente una chiamata asincrona in una chiamata sincrona, e quindi il chiamante non può essere asincrono (o asincrono) - almeno, non a causa della chiamata effettuata in "await".


1
In realtà, wait non aspetta i risultati: restituisce immediatamente una promessa. Questo è esattamente ciò che stavo cercando di trasmettere. Se wait effettivamente aspettato e non restituisse il controllo al chiamante, allora qualsiasi funzione che conteneva una parola chiave await non sarebbe letteralmente in grado di essere contrassegnata come asincrona. Ma invece di ciò, abbiamo qualsiasi funzione che contiene await o chiama una funzione che alla fine chiama una funzione contenente await deve essere asincrona. Fondamentalmente, se chiami in attesa anche una volta, tutte le tue funzioni devono essere contrassegnate come asincrone.
Rodney P. Barbati,

-5

Sì, wait / async era un ottimo concetto, ma l'implementazione è completamente rotta.

Per qualsiasi motivo, la parola chiave await è stata implementata in modo tale da poter essere utilizzata solo all'interno di un metodo asincrono. Questo è in realtà un bug, anche se non lo vedrai indicato come tale da nessuna parte ma proprio qui. La correzione di questo bug sarebbe l'implementazione della parola chiave await in modo tale che possa essere utilizzata solo PER CHIAMARE una funzione asincrona, indipendentemente dal fatto che la funzione chiamante sia sincrona o asincrona.

A causa di questo bug, se usi await per chiamare una vera funzione asincrona da qualche parte nel tuo codice, TUTTE le tue funzioni devono essere contrassegnate come asincrone e TUTTE le tue chiamate di funzione devono usare await.

Ciò significa essenzialmente che è necessario aggiungere il sovraccarico delle promesse a tutte le funzioni dell'intera applicazione, la maggior parte delle quali non sono e non saranno mai asincrone.

Se ci pensate davvero, l'uso di await in una funzione dovrebbe richiedere la funzione contenente la parola chiave await TO NOT BE ASYNC - questo perché la parola chiave await metterà in pausa l'elaborazione nella funzione in cui si trova la parola chiave await. Se l'elaborazione in quella funzione è sospesa, NON è sicuramente asincrona.

Quindi, per gli sviluppatori di javascript ed ECMAScript, correggi l'implementazione di await / async come segue ...

  • await può essere utilizzato solo per CALL funzioni asincrone.
  • wait può apparire in qualsiasi tipo di funzione, sincrona o asincrona.
  • Modificare il messaggio di errore da "await è valido solo nella funzione async" a "await può essere utilizzato solo per chiamare funzioni async".

Puoi chiamarlo un bug se vuoi, ma non sono d'accordo. Non esiste codice che "mette in pausa" - piuttosto, esiste codice che non può essere completato senza i risultati di qualche processo esterno (di solito io). Tale codice dovrebbe essere chiamato "asincrono" poiché molti processi esterni dovrebbero essere in grado di essere eseguiti contemporaneamente (in modo non sincrono), a differenza della VM javascript che è a thread singolo. Se si dispone di molte funzioni su cui è necessario eseguire il refactoring, asyncciò riflette il fatto che molte delle funzioni richiedono i risultati di processi esterni. Questo è del tutto canonico secondo me.
Gershom

Vale anche la pena menzionare un terribile inconveniente di limitare awaitl' usabilità solo con chiamate di funzione: per un singolo processo esterno, solo un singolo punto nel codice javascript potrebbe essere notificato quando quel processo è completo. Ad esempio, se il contenuto di un file è necessario per 3 scopi indipendenti, ogni scopo dovrebbe essere fatto in modo indipendente let content = await readTheFile();- questo perché la "promessa del contenuto del file" non può essere attesa, ma solo "l'atto di leggere il file e riprendere una volta che è stato leggere".
Gershom

Ok, non chiamiamolo codice che mette in pausa o codice che non può essere completato, ma che ne dici dell'attesa bloccata. Ecco il problema: la funzione che è bloccata in attesa o che non può essere completata è la funzione che contiene la parola chiave await. Non è la funzione asincrona che viene chiamata con la parola chiave await. Quindi, la funzione contenente la parola chiave await NON dovrebbe assolutamente essere contrassegnata come async - è bloccata in attesa, che è l'opposto di asynchronous.
Rodney P. Barbati

Per renderlo del tutto chiaro, considera quanto segue: await ha lo scopo di semplificare l'uso delle funzioni asincrone facendole sembrare sincrone (cioè mi permette di fare le cose in un ordine specifico). Forzare la funzione che contiene il await ad essere asincrono è un termine improprio completo: hai usato await in modo che diventi sincrono. Una funzione contenente un await è assolutamente, in ogni modo immaginabile, NON una funzione asincrona !!!
Rodney P. Barbati

1
@Gershom - sembra ragionevole. Grazie!
Rodney P. Barbati,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.