¿Por qué funciones asíncronas sobre síncronas?

Soy nuevo en NodeJS y me resulta un poco difícil trabajar con funciones asíncronas. Estoy tratando de averiguar los beneficios aquí. A continuación se presentan mis entendimientos sobre funciones asíncronas.

¿Puedes por favor validar cada uno de mis entendimientos a continuación?

  1. Las funciones asíncronas son buenas para usar cuando se ejecuta una operación independiente (desde el flujo del progtwig principal). No es ideal utilizar funciones asíncronas cuando el progtwig principal requiere mucho los datos / respuesta de la función asíncrona o cuando las diversas funciones asíncronas independientes están interconectadas.
  2. No es bueno depender del resultado de la salida de la función asíncrona en el flujo del progtwig principal. Porque Async siempre se ejecuta después del flujo principal. Entonces, si necesita que algunas funciones se ejecuten en el flujo principal, es bueno definirlo como Sincrónico, no asíncrono.
  3. Cuando se llama a funciones asíncronas independientes, es una práctica común llamar a la operación subsiguiente (función asíncrona), utilizando promesas o devoluciones de llamada.
  4. Todavía puedo llamar a una función de sincronización dentro de una función Async. ¿Pero si invoco una función asíncrona desde una función de sincronización, es posible que el progtwig no funcione como se espera, ya que la función asíncrona se ejecutará solo al final?

Muy bien, vamos a verlo pieza por pieza. Solo como base, recuerde que Node.js es un proceso de un solo subproceso y si necesita ejecutar blocking processes como leer un archivo (cree un puntero de evento, lea el identificador del archivo, configure la ruta del archivo, configure el modo abierto, etc.) es mejor usar funciones asíncronas que se ejecutan en un subproceso separado de la misma página o subproceso s / pool.


1) Las funciones asíncronas son buenas para usar cuando se ejecuta una operación independiente (desde el flujo del progtwig principal). No es ideal utilizar funciones asíncronas cuando el progtwig principal requiere mucho los datos / respuesta de la función asíncrona o cuando las diversas funciones asíncronas independientes están interconectadas.

Para empezar, no nos referiremos al archivo de progtwig como el main program ya que no hay subprogtwigs en el mundo de Node.js (no estoy hablando de módulos y similares).

Ahora, realmente tiene razón cuando dice que no debería usar ninguna función asíncrona cuando hay una necesidad inmediata de la salida. Tomemos el siguiente ejemplo:

 ... const data = readFile( 'fileName', ( data, output ) => { ... } ); console.log( data ); // this might be null or undefined 

En el caso anterior, no utilizaremos la función asíncrona (en el sentido tradicional). Sin embargo, con ES6 y superior, obtenemos el paradigma encantador async/await :

 const data = await readFile( 'filename' ); 

await hace la llamada pseudo-sync: se comporta como una función async , pero habrá un subproceso en pausa para esperar la salida. Así que, aquí, tienes toda la razón! Vamonos.


2) No es bueno depender del resultado de la salida de la función asíncrona en el flujo del progtwig principal. Porque Async siempre se ejecuta después del flujo principal. Entonces, si necesita que algunas funciones se ejecuten en el flujo principal, es bueno definirlo como Sincrónico, no asíncrono.

Aquí, usted dice que async opera después del flujo principal. Ahora, eso es incorrecto. Permítanme dibujar una imagen simple de las evaluaciones y ejecución de hilos:

Digamos que hay dos funciones de sync A() y B() , y sus hilos correspondientes son th__A y th__B , que irán de esta forma:

 th__a ---> th__b 

Si se disparan en el orden A() entonces B() . Espera la evaluación del primer proceso de sincronización (o locking) y luego ejecuta el segundo. Como es evidente, NO es después de que termine toda la ejecución.

Sin embargo, si ahora son funciones asíncronas, se ejecutarán en paralelo. Supongamos que A() era una función de sincronización y B() era una función asíncrona con los mismos nombres de subprocesos que el anterior, la ejecución es algo como esto:

 th__a ---- - - th__b -> 

Donde - representa un ciclo de reloj y -> representa el final de la ejecución. Podemos ver que A() se activa y luego, en un nuevo subproceso, B() se activa.

Supongo que esto tiene sentido. Ahora, volviendo, otra vez si necesita usarlos inmediatamente mientras tiene llamadas asíncronas, use await .


3) Cuando se llaman funciones asíncronas independientes, es una práctica común llamar a la operación subsiguiente (función asíncrona), utilizando promesas o devoluciones de llamada.

Absolutamente.

Digamos, definimos una función sayHello() :

 const sayHello = () => { const P = Q.defer(); // P.resolve(data); // or if there is an exception // P.reject(error); return p.promise; }; 

donde Q es la excelente biblioteca de promesas. Podemos llamarlo como:

 sayHello.then( ( data ) => { console.log( data ); // P.resolve(..) is working here since the promise was successful. } ).catch( ( err ) => { console.log( err ); // P.reject(..) is working here since there was a problem. } ); 

O puede usar fs.readFile(...) llamada como fs.readFile(...) :

 fs.readFile( 'fileName', ( e, data ) => { if( e ) { return console.log( e ); } // error was handled // perform subsequent functions here with data } ); 

4) ¿Todavía puedo llamar a una función de sincronización dentro de una función Async, pero el progtwig puede no funcionar como se espera si se llama a una función Async desde una función / operación de sincronización, ya que la función async se ejecutará solo en la última?

Realmente no. Consulte el punto (2). Se trata de hilos. Procesos no estáticos. Puede llamar a una función de sincronización dentro de una función asíncrona y funcionará perfectamente.

Cuando lea el archivo, diga que desea dividir los datos por \n o nueva línea:

 ... if( e ) { return console.log( e ); } const dataLines = e.split( '\n' ); // this will work brilliantly ... 

Espero que esto haya dejado todo claro! 🙂

Parece que aún no has estudiado sobre el bucle de eventos de javascript. Aquí hay un buen artículo que puedes seguir. Por lo general, en javascript, la función asíncrona se usa para evitar el retraso de IO (entrada / salida) en un proceso como una llamada HTTP en el navegador, el archivo leído en NodeJS, no el retraso de ejecución o la ejecución de parámetros, ya que un proceso javascript es de un solo hilo. Si desea estudiar más sobre la IO no bloqueadora, aquí hay un artículo que he escrito sobre cómo funciona, que parece responder todas sus preguntas.

Al escribir métodos asíncronos, como mencionaste, es difícil seguir cada callback y luego ejecutar nuevamente una llamada, una y otra vez, lo que se denomina infierno de callback en javascript. await async no es más que una solución simple para eso.

El uso real de la funcionalidad asíncrona en una aplicación javascript / node entra en juego cuando se trata de solicitudes de red y / o operaciones de E / S (o cosas que pueden llevar mucho tiempo).


Un ejemplo de llamada de red

Tome una aplicación de chat, por ejemplo. El cliente (usted) envía un mensaje a alguna persona A. El mensaje se envía al servidor o directamente al destinatario (p2p) para su posterior procesamiento de acuerdo con el modelo de comunicación. También desea enviar otro mensaje a otra persona; persona B. Pero si las solicitudes no se tratan de forma asíncrona, el cliente (usted) podría tener que esperar un período de tiempo indeterminado; dependiendo de la velocidad de su red, la velocidad de la red del destinatario, el tiempo de espera de la red o cualquier otro factor responsable.

Considere que tiene que esperar 2 unidades de tiempo para terminar su solicitud

 time: 1 2 3 4 5 action: SendToA(message) waitA waitA ResponseFromA SendToB(message) 

Pero si la misma petición es asíncrona. Usted envía la solicitud que es tratada de forma asíncrona por el cliente (para la comunicación p2p) o por el cliente y el servidor tanto para la comunicación (para el cliente / servidor). Esto es lo que realmente sucede en los navegadores. Los navegadores tratan las solicitudes de forma asíncrona, de modo que cualquier otra parte del código de su navegador no se atasque mientras espera a que finalice su solicitud.

 time: 1 2 3 4 5 action: SendToA(message) waitA/SendToB(message) waitA/waitB ResponseFromA ResponseFromB 

Por lo tanto, en el caso de sincronización, solo recibe una solicitud para tener éxito dentro de 5 unidades de tiempo, mientras que en el caso asíncrono obtiene dos solicitudes para tener éxito dentro de 5 unidades de tiempo.

nota : las implementaciones reales pueden diferir en unidades de tiempo, esto es solo una idea general de lo que realmente sucede.


Un ejemplo de E / S de lectura / escritura

La lectura / escritura de E / S es muy similar a una llamada de red; es decir, se necesita tiempo para terminar. Digamos que su aplicación tiene dos tablas que se leen de dos archivos diferentes y rellena cada una. Si trata ambas solicitudes de forma sincrónica, obtendrá un retraso masivo en su ejecución general, mientras que async ayuda.

Para sincronizar:

 time: 1 2 3 4 5 action: ReadFromFileA(message) waitA waitA ResponseFromA ReadFromFileB(message) 

Para async:

 time: 1 2 3 4 5 action: ReadFromFileA() ReadFromFileB() waitA/waitB ResponseFromA ResponseFromB 

Esta fue una explicación muy general de lo que pueden hacer las llamadas / funciones asíncronas. Sin embargo, async no siempre es lo que hay que hacer. Como mencionó en su pregunta, hay ocasiones en que necesita llamadas / funciones sincrónicas.

La impresión es una acción muy peculiar que tiene que ser sincrónica. No se pueden imprimir dos papeles de forma asíncrona.

Las funciones dependientes también deben estar sincronizadas.


Dicho todo esto, async es una característica muy potente si se usa correctamente. Hay (casi) siempre posibilidades de asincronía en una aplicación en tiempo real. Si su aplicación no la usa, su usuario puede quejarse de la mala experiencia de usuario en su aplicación.