aguardar só é válido na função assíncrona

129

Eu escrevi este código em lib/helper.js

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

e então tentei usá-lo em outro arquivo

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

Eu tenho um erro

"await só é válido na função assíncrona"

Qual é o problema?

j.doe
fonte
1
Bem, o problema é que awaitsó pode ser usado dentro de uma asyncfunção. Ou seja, awaittorna uma função assíncrona, por isso deve ser declarada como tal.
Pointy de
Qual é o erro atual?
acdcjunior
ainda o mesmo, SyntaxError:
await
Você precisa compartilhar mais contexto sobre seu código.
Ele

Respostas:

158

O erro não está se referindo a, myfunctionmas 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();



Eu uso a oportunidade desta questão de aconselhá-lo sobre um anti padrão conhecido usando awaito que é: return await.


ERRADO

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


CORRIGIR

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


Além disso, saiba que há um caso especial em que return awaité correto e importante: (usando try / catch)

Existem preocupações de desempenho com `return await`?

Grégory NEUT
fonte
Mas isso não está funcionando, atualizei meu código. Ainda recebo o mesmo erro
j.doe
@ j.doe Eu adicionei um trecho
Grégory NEUT
2
Obrigado, encontrei meu problema. Eu estava tentando fazer isso dentro de um retorno de chamada é a função start (). A solução foi: const start = async function (a, b) {task.get (options, async function (error, result1) {const result = await myfunction ('test', 'test');
j.doe
Considerando que o Node é um único thread. Isso não diminui a solicitação por minuto e também aumenta o atraso entre o preenchimento das solicitações.
Rishabh Dhiman
1
Vale a pena mencionar que no exemplo "CORRETO", não é necessário declarar startcomo uma asyncfunção (embora alguns optem por fazê-lo de qualquer maneira, para ser mais explícito)
Gershom
11

Quando recebi esse erro, descobri que havia uma chamada para a função map dentro da minha função "assíncrona", então essa mensagem de erro estava se referindo à função de mapa não estar marcada como "assíncrona". Eu resolvi esse problema pegando a chamada "esperar" da função de mapa e descobrindo alguma outra maneira de obter o comportamento esperado.

var myfunction = async function(x,y) {
    ....
    someArray.map(someVariable => { // <- This was the function giving the error
        return await someFunction(someVariable);
    });
}
John Langford
fonte
2
Esse foi o meu problema. Substituí a função map por um loop for, que foi uma solução fácil para mim. No entanto, esta solução pode não funcionar para você, dependendo do seu código.
Thomas
6
Para sua informação, você também pode fazersomeArray.map(async (someVariable) => { return await someFunction(someVariable)})
ptim de
1
O awaitem seu código é enganoso, porque Array.mapnão tratará a função como uma função assíncrona. Para ficar bem claro, após a conclusão da mapfunção, someFunctiontudo estará pendente. Se você quiser realmente esperar que as funções terminem, você deve escrever: await Promise.all(someArray.map(someVariable => someFunction(someVariable)))ou await Promise.all(someArray.map(someFunction))).
Grégory NEUT
9

Para usar await, seu contexto de execução precisa estar asyncna natureza

Como disse, você precisa definir a natureza de executing contextonde você está disposto a awaituma tarefa antes de qualquer coisa.

Basta colocar asyncantes da fndeclaração na qual sua asynctarefa será executada.

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

Explicação:

Na sua pergunta, você está importando um methodque está asynchronousna natureza e será executado em paralelo. Mas onde você está tentando executar esse asyncmétodo está dentro de um diferente execution contextque você precisa 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;

Querendo saber o que está acontecendo sob o capô

awaitconsome métodos / funções de promessa / futuro / retorno de tarefa e asyncmarca um método / função como capaz de usar o await.

Além disso, se você estiver familiarizado com o promises, awaitestá realmente fazendo o mesmo processo de promessa / resolução. Criar uma cadeia de promessas e executar a próxima tarefa no resolveretorno de chamada.

Para obter mais informações, você pode consultar o MDN DOCS .

Satyam Pathak
fonte
Mesmo com async na função de início, estou recebendo o erro
j.doe
Não tenho certeza de onde você está perdendo e recebendo esse erro, não existe uma explicação complexa para resolver esse erro.
Satyam Pathak
esta é uma resposta adequada e realmente explica o motivo sublinhado. votado.
linehrr
3

A implementação atual de async/ awaitsuporta apenas a awaitpalavra - chave dentro das asyncfunções. Altere a startassinatura da função para que você possa usar awaitdentro start.

 var start = async function(a, b) {

 }

Para os interessados, a proposta de nível superior awaitestá atualmente na Etapa 2: https://github.com/tc39/proposal-top-level-await

user835611
fonte
1
Infelizmente, o que isso basicamente significa é que você terá que tornar TODAS as suas funções assíncronas, em toda a sua base de código. Porque se você quiser usar o await, você deve fazê-lo em uma função assíncrona, o que significa que você deve esperar a resposta dessa função na função que a chama - novamente, isso significa que TODAS as suas funções precisarão se tornar assíncronas. Para mim, isso significa que o await async não está pronto para uso. Quando você pode usar await para chamar um método assíncrono, independentemente de a função atual ser síncrona ou assíncrona, ela estará pronta para o horário nobre.
Rodney P. Barbati
1
Cada função que é através de qualquer nível de engano dependente dos resultados de um processo deve externa, e deveria ser definido com async- que é o todo ponto de async.
Gershom
Você pode atualmente usá-lo no nó repl usando a --experimental-repl-awaitopção.
lodz
3

Eu tive o mesmo problema e o seguinte bloco de código estava apresentando a mesma mensagem de erro:

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

O problema é que o método getCommits () era assíncrono, mas eu estava passando para ele o argumento repo, que também foi produzido por uma Promise. Então, eu tive que adicionar a palavra async a ele assim: async (repo) e ele começou a funcionar:

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

async / await é o mecanismo de manipulação de promessa, duas maneiras de fazer isso

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

            });

ou podemos usar await para aguardar a promessa de preenchimento completo primeiro, o que significa que foi rejeitada ou resolvida.

Agora, se quisermos usar await (aguardando o cumprimento de uma promessa) dentro de uma função, é obrigatório que a função de contêiner seja uma função assíncrona porque estamos aguardando que uma promessa seja cumprida de forma assíncrona || faz sentido certo ?.

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);
        });
senhor
fonte
-2

"await só é válido na função assíncrona"

Mas por que? 'await' transforma explicitamente uma chamada assíncrona em uma chamada síncrona e, portanto, o chamador não pode ser assíncrono (ou asyncable) - pelo menos, não por causa da chamada sendo feita em 'await'.

mn_test347
fonte
1
Na verdade, await não espera pelos resultados - ele imediatamente retorna uma promessa. Isso é exatamente o que eu estava tentando transmitir. Se await realmente esperou e não devolveu o controle ao chamador, qualquer função que contivesse uma palavra-chave await literalmente não poderia ser marcada como assíncrona. Mas, em vez disso, temos qualquer função que contém await ou chama uma função que eventualmente chama uma função contendo await deve ser assíncrona. Basicamente, se você chamar e esperar pelo menos uma vez - todas as suas funções devem ser marcadas como assíncronas.
Rodney P. Barbati
-5

Sim, await / async era um ótimo conceito, mas a implementação está completamente quebrada.

Por algum motivo, a palavra-chave await foi implementada de forma que só pode ser usada em um método assíncrono. Na verdade, isso é um bug, embora você não vá vê-lo referido como tal em nenhum lugar, exceto aqui. A correção para esse bug seria implementar a palavra-chave await de forma que ela só pudesse ser usada PARA CALL uma função assíncrona, independentemente de a própria função de chamada ser síncrona ou assíncrona.

Devido a esse bug, se você usar await para chamar uma função assíncrona real em algum lugar do código, TODAS as funções devem ser marcadas como assíncronas e TODAS as chamadas de função devem usar await.

Isso significa essencialmente que você deve adicionar a sobrecarga de promessas a todas as funções em todo o seu aplicativo, a maioria das quais não são e nunca serão assíncronas.

Se você realmente pensar sobre isso, o uso de await em uma função deve exigir a função que contém a palavra-chave await TO NOT BE ASYNC - isso ocorre porque a palavra-chave await vai pausar o processamento na função onde a palavra-chave await é encontrada. Se o processamento nessa função for pausado, então definitivamente NÃO é assíncrono.

Portanto, para os desenvolvedores de javascript e ECMAScript - corrija a implementação de await / async como segue ...

  • await só pode ser usado para funções assíncronas CALL.
  • O await pode aparecer em qualquer tipo de função, síncrona ou assíncrona.
  • Altere a mensagem de erro de "await só é válido na função assíncrona" para "await só pode ser usado para chamar funções assíncronas".
Rodney P. Barbati
fonte
Você pode chamar de bug, se quiser, mas eu discordo. Não existe código que "pausa" - em vez disso, existe código que não pode ser concluído sem os resultados de algum processo externo (geralmente io). Esse código deve ser chamado de "assíncrono", pois muitos processos externos devem ser capazes de rodar ao mesmo tempo (não sincronizadamente), ao contrário da VM javascript que é de thread único. Se você tem muitas funções que precisam ser refatoradas, asyncisso reflete o fato de que muitas de suas funções requerem os resultados de processos externos. Isso é completamente canônico na minha opinião.
Gershom
Também vale a pena mencionar a terrível desvantagem de restringir awaitpara ser utilizável apenas com chamadas de função: para um único processo externo, apenas um único ponto no código javascript pode ser notificado quando esse processo for concluído. Por exemplo, se o conteúdo de um arquivo for necessário para 3 finalidades independentes, cada finalidade precisaria realizar de forma independente let content = await readTheFile();- isso ocorre porque a "promessa do conteúdo do arquivo" não pode ser esperada, apenas "o ato de ler o arquivo e retomar uma vez que tenha sido ler".
Gershom
Ok, não vamos chamá-lo de código que pausa ou código que não pode ser concluído, mas que tal espera bloqueada. Aqui está o problema - a função que está bloqueada em espera ou que não pode ser concluída é a função que contém a palavra-chave await. Não é a função assíncrona que está sendo chamada com a palavra-chave await. Portanto, a função que contém a palavra-chave await definitivamente NÃO deve ser marcada como assíncrona - ela é bloqueada em espera, que é o oposto de assíncrona.
Rodney P. Barbati
Para tornar isso totalmente claro, considere o seguinte - await tem como objetivo simplificar o uso de funções assíncronas, fazendo-as parecer síncronas (ou seja, permite que eu faça coisas em uma ordem específica). Forçar a função que contém o await a ser assíncrono é um equívoco completo - você usou o await para que ele se tornasse síncrono. Uma função contendo um await é absolutamente, de todas as maneiras concebíveis, NÃO uma função assíncrona !!!
Rodney P. Barbati
1
@Gershom - isso parece razoável. Obrigado!
Rodney P. Barbati