No pude entender el orden de ejecución de los dos códigos a continuación.
async function main(test) { while(1) console.log(test); } main("a"); main("b");Este código anterior registra una "a" infinita.
async function main(test) { while(1) await console.log(test); } main("a"); main("b");Mientras que este código anterior registra infinitos "a" y "b".
Quería entender mejor async/await, pero este comportamiento anterior me confundió. ¿Cómo se manejan esas funciones de registro por el bucle de eventos?
Una función async se ejecuta de forma síncrona hasta el primer await , return o return implícito (el código se cae al final de la función). Eso es para que pueda iniciar el proceso asíncrono del que luego informará la finalización (estableciendo la promesa que devuelve). Entonces, su primer ejemplo registra a para siempre porque eso lo hace la parte síncrona de la primera llamada a main ; la ejecución nunca llega a la segunda llamada a main .
Su segundo ejemplo introduce la asincronía al agregar await (no importa que lo que await esté esperando no sea una promesa [ console.log devuelve undefined ]; se envuelve en uno). Eso significa que la primera llamada a main se ejecuta sincrónicamente hasta después del primer console.log , luego se detiene y devuelve una promesa mientras espera que se establezca la promesa envuelta alrededor de undefined Eso permite que la segunda llamada a main avance, haciendo lo la misma cosa. En ese momento, el código que realiza las llamadas a main está completo y se puede ejecutar cualquier devolución de llamada de promesa pendiente. La primera devolución de llamada de promesa pendiente es para await en la primera llamada a main , por lo que la llamada realiza otra iteración de bucle; la segunda promesa pendiente es para await en la segunda llamada a main , por lo que hace otra iteración de bucle; Y así sucesivamente y así sucesivamente y así sucesivamente.
Mencionaste "concurrencia". Las dos llamadas a main en su segundo ejemplo se ejecutan simultáneamente pero no son de subprocesos múltiples; en cambio, cada uno de ellos alternativamente obtiene acceso al hilo principal brevemente hasta su próximo await . JavaScript funciona en un modelo de un subproceso por "reino" (en términos generales, por entorno global). Por lo tanto, no tiene que preocuparse por problemas de subprocesos como operaciones reordenadas o cachés obsoletos como lo haría en un entorno de subprocesos múltiples (a menos que esté usando memoria compartida , pero no está en ese código); solo hay un hilo.
¹ Técnicamente, la promesa ya está resuelta en este caso antes de await comience a esperarla (porque es solo una promesa envuelta alrededor de undefined ), pero cuando adjuntas una promesa, nunca activa tu código sincrónicamente, incluso si la promesa ya está resuelta.
El uso de funciones asincrónicas dentro de Javascript generalmente resuelve datos que no están fácilmente disponibles. Los ejemplos incluyen llamar desde una base de datos y raspar páginas web en busca de datos.
El código proporcionó bucles infinitos porque no hay final para dicho bucle ( while ). En el contexto del código provisto, while(1) siempre será verdadero, ya que no hay condición para indicar lo contrario. En el uso práctico, los bucles están diseñados para cesar cuando se cumple una condición.
Aquí hay un ejemplo básico del uso de un bucle while procedente de MDN Docs que cubre el descanso
let n = 0; while (n < 3) { n++; } console.log(n); // expected output: 3Para comprender mejor la programación asíncrona dentro de Javascript, recomiendo encarecidamente los documentos de MDN Docs sobre funciones asíncronas.
Para responder a su pregunta sobre las interacciones del registro de la consola con await : JS 'congelará' el script cuando lea await y trabajará para completar sus acciones definidas, luego volverá a leer la siguiente línea. En el contexto del código, Javascript está haciendo su trabajo. Regresa a la falta de una break o condición para el bucle.