Estaba intentando encadenar dos funciones asíncronas juntas, porque la primera tenía un parámetro de retorno condicional que hacía que la segunda se ejecutara o saliera del módulo. Sin embargo, encontré un comportamiento extraño que no puedo encontrar en las especificaciones.
async function isInLobby() {
//promise.all([chained methods here])
let exit = false;
if (someCondition) exit = true;
}
Este es un fragmento bastardo de mi código (puede ver el alcance completo aquí ), que simplemente verifica si un jugador ya está en un lobby, pero eso es irrelevante.
A continuación, tenemos esta función asincrónica.
async function countPlayer() {
const keyLength = await scardAsync(game);
return keyLength;
}
Esta función no necesita ejecutarse si exit === true
.
Traté de hacer
const inLobby = await isInLobby();
Esto esperaba que esperara los resultados, por lo que puedo usarlo inLobby
para ejecutar condicionalmente countPlayer
, sin embargo, recibí un error de tipo sin detalles específicos.
¿Por qué no puede realizar await
una async
función fuera del alcance de la función? Sé que es una promesa de azúcar, por lo que debe estar encadenada, then
pero ¿por qué countPlayer
puedo esperar otra promesa adentro , pero afuera no puedo await
isInLobby
?
fuente
await isInLobby()
y cómoinLobby
se usa? Además, ¿dónde / cómo secountPlayer
llama?isInLobby().then( … countPlayer().then …
parte, la solución es trivial: simplemente haga la función en la que están contenidas esas llamadas (la(req, res) =>
única)async
.await
para tu código? Es por eso que me pregunto si aceptaste la respuesta que realmente no se relaciona con el problema de la pregunta.Respuestas:
El nivel superior
await
no es compatible. Hay algunas discusiones por parte del comité de estándares sobre por qué esto es así, como este problema de Github .También hay un artículo de reflexión en Github sobre por qué esperar de nivel superior es una mala idea. Específicamente, sugiere que si tiene un código como este:
// data.js const data = await fetch( '/data.json' ); export default data;
Ahora, cualquier archivo que importe
data.js
no se ejecutará hasta que se complete la recuperación, por lo que toda la carga de su módulo ahora está bloqueada. Esto hace que sea muy difícil razonar sobre el orden de los módulos de la aplicación, ya que estamos acostumbrados a que Javascript de nivel superior se ejecute de forma sincrónica y predecible. Si esto estuviera permitido, saber cuándo se define una función se vuelve complicado.Mi perspectiva es que es una mala práctica que su módulo tenga efectos secundarios simplemente cargándolo. Eso significa que cualquier consumidor de su módulo tendrá efectos secundarios simplemente al requerir su módulo. Esto limita gravemente dónde se puede utilizar su módulo. Un nivel superior
await
probablemente significa que está leyendo desde alguna API o llamando a algún servicio en el momento de la carga. En su lugar, debería exportar funciones asíncronas que los consumidores puedan utilizar a su propio ritmo.fuente
void async function() { const inLobby = await isInLobby() }()
inLobby
para la función que la hace no accesible?.then()
(lo siento, debería haberlo dejado un poco más claro).Siempre hay esto, por supuesto:
(async () => { await ... // all of the script.... })(); // nothing else
Esto hace una función rápida con async donde puede usar await. ¡Te ahorra la necesidad de hacer una función asíncrona que es genial! // créditos Silve2611
fuente
await
esta función anónima, que nuevamente, no funciona desde fuera de las funciones.Aún mejor es poner un punto y coma adicional delante del bloque de código
;(async () => { await ... })();
Esto evita que el formateador automático (por ejemplo, en vscode) mueva el primer paréntesis al final de la línea anterior.
El problema se puede demostrar en el siguiente ejemplo:
const add = x => y => x+y const increment = add(1) (async () => { await ... })();
Sin el punto y coma, se volverá a formatear como:
const add = x => y => x+y const increment = add(1)(async () => { await Promise(1) })()
lo cual obviamente es incorrecto porque asigna la función asíncrona como
y
parámetro e intenta llamar a una función desde el resultado (que en realidad es una cadena extraña'1async () => {...}'
)fuente
add(1);
y coma después y no antes de la función asincrónica.A partir de Node.js 14.3.0, se admite la espera de nivel superior.
Bandera requerido:
--experimental-top-level-await
.Más detalles: https://v8.dev/features/top-level-await
fuente
puede hacer espera de nivel superior desde mecanografiado 3.8
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#-top-level-await
De la publicación:
Esto se debe a que anteriormente en JavaScript (junto con la mayoría de los otros lenguajes con una característica similar), await solo se permitía dentro del cuerpo de una función asincrónica. Sin embargo, con await de nivel superior, podemos usar await en el nivel superior de un módulo.
const response = await fetch("..."); const greeting = await response.text(); console.log(greeting); // Make sure we're a module export {};
Tenga en cuenta que hay una sutileza: la espera de nivel superior solo funciona en el nivel superior de un módulo, y los archivos solo se consideran módulos cuando TypeScript encuentra una importación o una exportación. En algunos casos básicos, es posible que deba escribir export {} como un texto estándar para asegurarse de esto.
Es posible que la espera de nivel superior no funcione en todos los entornos en los que podría esperar en este momento. Actualmente, solo puede usar el nivel superior de espera cuando la opción del compilador de destino es es2017 o superior, y el módulo es esnext o system. El soporte dentro de varios entornos y paquetes puede ser limitado o puede requerir la habilitación del soporte experimental.
fuente