await solo es válido en función asincrónica

130

Escribí este código en lib/helper.js

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

y luego intenté usarlo en otro archivo

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

Tengo un error

"await solo es válido en función asincrónica"

¿Cual es el problema?

j.doe
fuente
1
Bueno, el problema es que awaitsolo se puede usar dentro de una asyncfunción. Es decir, awaithace que una función sea asíncrona, por lo que debe declararse como tal.
Puntiagudo
¿Cuál es el error actual?
acdcjunior
sigue siendo el mismo, SyntaxError: await solo es válido en la función asincrónica
j.doe
Necesita compartir más contexto sobre su código.
Ele

Respuestas:

159

El error no se refiere a myfunctionsino 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();



Yo uso la oportunidad de esta pregunta para aconsejarle sobre un patrón conocido de lucha contra el uso de awaitlo que es: return await.


INCORRECTO

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


CORRECTO

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


Además, sepa que hay un caso especial donde return awaites correcto e importante: (usando try / catch)

¿Hay problemas de rendimiento con el "retorno en espera"?

Grégory NEUT
fuente
Pero esto no funciona, actualicé mi código. Sigo recibiendo el mismo error
j.doe
@ j.doe He agregado un fragmento
Grégory NEUT
2
Gracias, encontré mi problema. Estaba tratando de hacerlo dentro de una devolución de llamada es la función start (). La solución fue: const start = async function (a, b) {task.get (options, async function (error, result1) {const result = await myfunction ('test', 'test');
j.doe
Teniendo en cuenta que Node es un solo subproceso. ¿No disminuye la solicitud por minutos y también aumenta el retraso entre solicitudes de cumplimiento?
Rishabh Dhiman
1
Vale la pena mencionar que en el ejemplo "CORRECTO", no es necesario declarar startcomo una asyncfunción (aunque algunos optarán por hacerlo de todos modos, para ser más explícitos)
Gershom
11

Cuando recibí este error, resultó que tenía una llamada a la función de mapa dentro de mi función "asíncrona", por lo que este mensaje de error en realidad se refería a que la función de mapa no estaba marcada como "asíncrona". Solucioné este problema eliminando la llamada "await" de la función del mapa y encontrando alguna otra forma de obtener el comportamiento esperado.

var myfunction = async function(x,y) {
    ....
    someArray.map(someVariable => { // <- This was the function giving the error
        return await someFunction(someVariable);
    });
}
John Langford
fuente
2
Este fue el problema para mí. Reemplacé la función de mapa con un bucle for, que fue una solución fácil para mí. Sin embargo, es posible que esta solución no funcione para usted según su código.
Thomas
6
Para su información, también puede hacerlosomeArray.map(async (someVariable) => { return await someFunction(someVariable)})
ptim
1
El awaiten su código es engañoso, porque Array.mapno manejará la función como una función asincrónica. Para que quede perfectamente claro, una vez finalizada la mapfunción, someFunctiontodo estará pendiente. Si realmente quieres esperar a que terminen las funciones tienes que escribir: await Promise.all(someArray.map(someVariable => someFunction(someVariable)))o await Promise.all(someArray.map(someFunction))).
Grégory NEUT
9

Para usar await, su contexto de ejecución debe estar asyncen la naturaleza

Como se dijo, debe definir la naturaleza de su executing contextlugar en el que está dispuesto a realizar awaituna tarea antes que nada.

Simplemente coloque asyncantes de la fndeclaración en la que asyncse ejecutará su tarea.

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

Explicación:

En su pregunta, está importando un archivo methodque está asynchronousen la naturaleza y se ejecutará en paralelo. Pero donde está intentando ejecutar ese asyncmétodo es dentro de un diferente execution contextque debe definir asyncpara usar await.

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

Preguntándome qué pasa bajo el capó

awaitconsume métodos / funciones de promesa / futuro / devolución de tareas y asyncmarca un método / función como capaz de usar await.

Además, si está familiarizado promises, en awaitrealidad está haciendo el mismo proceso de promesa / resolución. Crea una cadena de promesas y ejecuta su próxima tarea en la resolvedevolución de llamada.

Para obtener más información, puede consultar MDN DOCS .

Satyam Pathak
fuente
Incluso con async en la función de inicio
aparece
No estoy seguro de dónde falta y dónde aparece este error, no existe una explicación tan compleja para resolver este error.
Satyam Pathak
esta es una respuesta adecuada y en realidad explica la razón del subrayado. votado.
linehrr
3

La implementación actual de async/ awaitsolo admite la awaitpalabra clave dentro de las asyncfunciones. Cambie la startfirma de su función para que pueda usarla awaitdentro start.

 var start = async function(a, b) {

 }

Para los interesados, la propuesta de nivel superior se awaitencuentra actualmente en la Etapa 2: https://github.com/tc39/proposal-top-level-await

user835611
fuente
1
Desafortunadamente, lo que esto significa básicamente es que tendrás que hacer que TODAS tus funciones sean asincrónicas, en toda tu base de código. Porque si desea usar await, debe hacerlo en una función asíncrona, lo que significa que debe esperar la respuesta de esa función en la función que la llama; nuevamente, significa que TODAS sus funciones deberán volverse asíncronas. Para mí, esto significa que await async no está listo para usarse. Cuando pueda usar await para llamar a un método asincrónico, independientemente de si la función actual es sincrónica o asincrónica, estará lista para el horario de máxima audiencia.
Rodney P. Barbati
1
Cada función que depende de cualquier nivel de indirección de los resultados de un proceso externo debe, y debe definirse con async, ese es el objetivo de async.
Gershom
Actualmente puede usarlo en la respuesta de nodo usando la --experimental-repl-awaitopción.
Lodge
3

Tuve el mismo problema y el siguiente bloque de código estaba dando el mismo mensaje de error:

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

El problema es que el método getCommits () era asíncrono pero le estaba pasando el repositorio de argumentos que también fue producido por Promise. Entonces, tuve que agregar la palabra async así: async (repo) y comenzó a funcionar:

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

async / await es el mecanismo de manejo de la promesa, dos formas en que podemos hacerlo

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

            });

o podemos usar await para esperar a que la promesa se complete por completo primero, lo que significa que se rechaza o se resuelve.

Ahora, si queremos usar await (esperando que se cumpla una promesa) dentro de una función, es obligatorio que la función contenedora sea una función asíncrona porque estamos esperando que una promesa se cumpla de forma asincrónica || tiene sentido ¿verdad ?.

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);
        });
Señor
fuente
-2

"await solo es válido en función asincrónica"

¿Pero por qué? 'await' convierte explícitamente una llamada asíncrona en una llamada síncrona y, por lo tanto, la persona que llama no puede ser asíncrona (o asincable), al menos, no porque la llamada se realice en 'espera'.

mn_test347
fuente
1
En realidad, await no espera resultados, devuelve inmediatamente una promesa. Esto es exactamente lo que estaba intentando transmitir. Si await realmente esperó y no devolvió el control a la persona que llama, entonces cualquier función que contenga una palabra clave await literalmente no podrá marcarse como asíncrona. Pero en lugar de eso, tenemos cualquier función que contenga await o llame a una función que eventualmente llame a una función que contenga await debe ser asíncrona. Básicamente, si llama a await aunque sea una vez, todas sus funciones deben estar marcadas como asíncronas.
Rodney P. Barbati
-5

Sí, await / async fue un gran concepto, pero la implementación está completamente rota.

Por alguna razón, la palabra clave await se ha implementado de tal manera que solo se puede usar dentro de un método asincrónico. De hecho, esto es un error, aunque no verá que se mencione como tal en ningún otro lugar que no sea aquí. La solución para este error sería implementar la palabra clave await de manera que solo se pueda usar PARA LLAMAR a una función asíncrona, independientemente de si la función de llamada es en sí misma síncrona o asíncrona.

Debido a este error, si usa await para llamar a una función asíncrona real en algún lugar de su código, TODAS sus funciones deben estar marcadas como asíncronas y TODAS sus llamadas a funciones deben usar await.

Básicamente, esto significa que debe agregar la sobrecarga de las promesas a todas las funciones en toda su aplicación, la mayoría de las cuales no son y nunca serán asincrónicas.

Si realmente lo piensa, el uso de await en una función debería requerir que la función que contiene la palabra clave await NO SEA ASINC. Esto se debe a que la palabra clave await pausará el procesamiento en la función donde se encuentra la palabra clave await. Si el procesamiento en esa función está en pausa, definitivamente NO es asíncrono.

Entonces, para los desarrolladores de javascript y ECMAScript, corrijan la implementación de await / async de la siguiente manera ...

  • await solo se puede usar para LLAMAR funciones asíncronas.
  • await puede aparecer en cualquier tipo de función, sincrónica o asincrónica.
  • Cambie el mensaje de error de "await solo es válido en función asíncrona" a "await solo se puede usar para llamar funciones asíncronas".
Rodney P. Barbati
fuente
Puedes llamarlo error si quieres, pero no estoy de acuerdo. No existe el código que se "pausa"; más bien, hay código que no puede completarse sin los resultados de algún proceso externo (generalmente io). Dicho código debería llamarse "asincrónico", ya que muchos procesos externos deberían poder ejecutarse al mismo tiempo (de forma no sincrónica), en contraste con la máquina virtual javascript que es de un solo subproceso. Si tiene muchas funciones a las que se debe refactorizar, asynceso refleja el hecho de que muchas de sus funciones requieren los resultados de procesos externos. Eso es completamente canónico en mi opinión.
Gershom
También vale la pena mencionar un terrible inconveniente de restringir awaitpara que solo se pueda usar con llamadas a funciones: para un solo proceso externo, solo un solo punto en el código javascript puede ser notificado cuando ese proceso se completa. Por ejemplo, si el contenido de un archivo es necesario para 3 propósitos independientes, cada propósito debería hacerlo de forma independiente let content = await readTheFile();; esto se debe a que no se puede esperar la "promesa del contenido del archivo", solo "el acto de leer el archivo y reanudar una vez que se ha leer".
Gershom
Ok, no lo llamemos código que hace una pausa o código que no se puede completar, pero ¿qué tal la espera bloqueada? Aquí está el problema: la función que está bloqueada en espera o que no se puede completar es la función que contiene la palabra clave await. No es la función asíncrona la que se llama con la palabra clave await. Por lo tanto, la función que contiene la palabra clave await definitivamente NO debería tener que estar marcada como asíncrona, está bloqueada en espera, que es lo opuesto a asincrónica.
Rodney P. Barbati
Para dejar esto completamente claro, considere lo siguiente: await tiene la intención de simplificar el uso de funciones asincrónicas haciéndolas parecer sincrónicas (es decir, me permite hacer las cosas en un orden específico). Forzar la función que contiene la espera para que sea asíncrona es un nombre completamente inapropiado: usó await para que se vuelva sincrónica. ¡Una función que contiene un await es absolutamente, de todas las formas posibles, NO una función asíncrona!
Rodney P. Barbati
1
@Gershom, eso suena razonable. ¡Gracias!
Rodney P. Barbati