Eu estava tentando encadear duas funções assíncronas, porque a primeira tinha um parâmetro de retorno condicional que fazia a segunda executar ou sair do módulo. No entanto, encontrei um comportamento estranho que não consigo encontrar nas especificações.
async function isInLobby() {
//promise.all([chained methods here])
let exit = false;
if (someCondition) exit = true;
}
Este é um snippet bastardizado do meu código (você pode ver o escopo completo aqui ), que simplesmente verifica se um jogador já está em um lobby, mas isso é irrelevante.
Em seguida, temos essa função assíncrona.
async function countPlayer() {
const keyLength = await scardAsync(game);
return keyLength;
}
Esta função não precisa ser executada se exit === true
.
Eu tentei fazer
const inLobby = await isInLobby();
Esperava que este fosse aguardar os resultados, então posso usar inLobby
para executar condicionalmente countPlayer
, porém recebi um erro de tipo sem detalhes específicos.
Por que você não pode await
uma async
função fora do escopo da função? Eu sei que é uma promessa de açúcar, então deve ser acorrentada, then
mas por que em countPlayer
eu posso esperar outra promessa, mas fora, eu não posso await
isInLobby
?
fonte
await isInLobby()
e comoinLobby
é usado? Além disso, onde / como écountPlayer
chamado?isInLobby().then( … countPlayer().then …
parte, a solução é trivial: basta fazer a função na qual essas chamadas estão contidas ((req, res) =>
aquela)async
.await
para o seu código? É por isso que me perguntei se você aceitou a resposta que realmente não se relaciona com o problema da pergunta.Respostas:
O nível superior
await
não é compatível. Existem algumas discussões pelo comitê de padrões sobre o motivo disso, como este problema no Github .Há também um artigo no Github sobre por que esperar de nível superior é uma má ideia. Especificamente, ele sugere que, se você tiver um código como este:
// data.js const data = await fetch( '/data.json' ); export default data;
Agora, qualquer arquivo importado
data.js
não será executado até que a busca seja concluída, portanto, todo o carregamento do módulo está bloqueado. Isso torna muito difícil raciocinar sobre a ordem do módulo do app, já que estamos acostumados com o Javascript de nível superior executando de forma síncrona e previsível. Se isso fosse permitido, saber quando uma função é definida torna-se complicado.Minha perspectiva é que não é uma boa prática seu módulo ter efeitos colaterais simplesmente por carregá-lo. Isso significa que qualquer consumidor de seu módulo terá efeitos colaterais simplesmente exigindo seu módulo. Isso limita muito onde seu módulo pode ser usado. Um nível superior
await
provavelmente significa que você está lendo alguma API ou chamando algum serviço no momento do carregamento. Em vez disso, você deve apenas exportar funções assíncronas que os consumidores possam usar em seu próprio ritmo.fonte
void async function() { const inLobby = await isInLobby() }()
inLobby
a função tornando-a inacessível?.then()
(desculpe, deveria ter deixado isso um pouco mais claro).Sempre há isso, é claro:
(async () => { await ... // all of the script.... })(); // nothing else
Isso torna uma função rápida com async onde você pode usar await. Isso elimina a necessidade de criar uma função assíncrona, o que é ótimo! // créditos Silve2611
fonte
await
dessa função anônima, que novamente, não funciona fora das funções.Melhor ainda é colocar um ponto-e-vírgula adicional antes do bloco de código
;(async () => { await ... })();
Isso evita que o formatador automático (por exemplo, em vscode) mova o primeiro parênteses para o final da linha anterior.
O problema pode ser demonstrado no seguinte exemplo:
const add = x => y => x+y const increment = add(1) (async () => { await ... })();
Sem o ponto-e-vírgula, isso será reformatado como:
const add = x => y => x+y const increment = add(1)(async () => { await Promise(1) })()
o que obviamente está errado porque atribui a função assíncrona como
y
parâmetro e tenta chamar uma função a partir do resultado (que na verdade é uma string estranha'1async () => {...}'
)fonte
add(1);
e- vírgula depois e não antes da função assíncrona.A partir do Node.js 14.3.0, o await de nível superior é compatível.
Bandeira necessário:
--experimental-top-level-await
.Mais detalhes: https://v8.dev/features/top-level-await
fonte
você pode fazer o nível superior esperar desde o typescript 3.8
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#-top-level-await
Do post:
Isso ocorre porque anteriormente em JavaScript (junto com a maioria das outras linguagens com um recurso semelhante), await só era permitido dentro do corpo de uma função assíncrona. No entanto, com o await de nível superior, podemos usar o await no nível superior de um módulo.
const response = await fetch("..."); const greeting = await response.text(); console.log(greeting); // Make sure we're a module export {};
Observe que há uma sutileza: aguardar de nível superior funciona apenas no nível superior de um módulo, e os arquivos são considerados módulos apenas quando o TypeScript encontra uma importação ou exportação. Em alguns casos básicos, pode ser necessário escrever export {} como um boilerplate para ter certeza disso.
Aguardar de nível superior pode não funcionar em todos os ambientes em que você poderia esperar neste momento. Atualmente, você só pode usar o nível superior esperar quando a opção do compilador alvo for es2017 ou superior e o módulo for esnext ou sistema. O suporte em vários ambientes e bundlers pode ser limitado ou pode exigir a ativação do suporte experimental.
fonte