¿Cuál es la diferencia entre la programación síncrona y asíncrona (en node.js)

189

He estado leyendo nodebeginner y me encontré con las siguientes dos piezas de código.

El primero:

    var result = database.query("SELECT * FROM hugetable");
    console.log("Hello World");

El segundo:

    database.query("SELECT * FROM hugetable", function(rows) {
       var result = rows;
    });
    console.log("Hello World");

Entiendo lo que se supone que deben hacer, consultan la base de datos para recuperar la respuesta a la consulta. Y entoncesconsole.log('Hello world') .

El primero es un código supuestamente sincrónico. Y el segundo es el código asincrónico.

La diferencia entre las dos piezas es muy vaga para mí. ¿Cuál sería la salida?

Buscar en Google en programación asincrónica tampoco me ayudó.

Azeirah
fuente
41
Es extraño que no hayas encontrado nada con google, es un tema bastante importante. En la programación síncrona, cada paso se realiza uno después de que el anterior haya terminado de ejecutarse. En asíncrono, el paso 2 se realizará incluso si el paso 1 no está terminado. La función que ve definida en su segundo ejemplo se llama función callBack, y se ejecutará tan pronto como se devuelva el resultado de la base de datos, que probablemente será después de que se ejecute console.log.
Laurent S.
77
@Bartdude Había mucha programación asíncrona, pero no había una explicación algo simple sobre qué es y qué significa en la práctica.
Azeirah
1
@GabrielLlamas ¿Por qué debemos evitar las funciones sincrónicas?
Charlie Parker
3
@CharlieParker Debido a que bloquean el bucle de eventos y está perdiendo todos los beneficios de un modelo de E / S con eventos asíncronos. Y porque es una mala práctica. Piénselo de esta manera: si no está usando funciones asincrónicas, ¿por qué está usando Node.js?
Gabriel Llamas
1
@GabrielLlamas, si estoy ejecutando una consulta INSERT y quiero usar la última ID insertada después database.query(), entonces debería llamarla como sincronizada, ¿verdad? o cuál debería ser el enfoque? (Esta pregunta la tengo desde hace mucho tiempo)
San

Respuestas:

225

La diferencia es que en el primer ejemplo , el programa bloqueará en la primera línea. La siguiente línea ( console.log) tendrá que esperar.

En el segundo ejemplo , console.logse ejecutará MIENTRAS se procesa la consulta. Es decir, la consulta se procesará en segundo plano, mientras su programa está haciendo otras cosas, y una vez que los datos de la consulta estén listos, hará lo que quiera con ella.

En pocas palabras: el primer ejemplo se bloqueará, mientras que el segundo no.

La salida de los siguientes dos ejemplos:

// Example 1 - Synchronous (blocks)
var result = database.query("SELECT * FROM hugetable");
console.log("Query finished");
console.log("Next line");


// Example 2 - Asynchronous (doesn't block) 
database.query("SELECT * FROM hugetable", function(result) {
    console.log("Query finished");
});
console.log("Next line");

Sería:

  1. Query finished
    Next line
  2. Next line
    Query finished

Nota
Si bien el nodo en sí es de un solo subproceso , hay algunas tareas que pueden ejecutarse en paralelo. Por ejemplo, las operaciones del sistema de archivos ocurren en un proceso diferente.

Es por eso que Node puede realizar operaciones asíncronas: un subproceso está realizando operaciones del sistema de archivos, mientras que el subproceso principal del Nodo sigue ejecutando su código javascript. En un servidor controlado por eventos como Node, el subproceso del sistema de archivos notifica al subproceso principal del Nodo de ciertos eventos, como finalización, falla o progreso, junto con cualquier dato asociado con ese evento (como el resultado de una consulta a la base de datos o un error mensaje) y el hilo principal del Nodo decide qué hacer con esos datos.

Puede leer más sobre esto aquí: Cómo funciona el modelo de E / S sin bloqueo de un solo subproceso en Node.js

Salvatorelab
fuente
9
Así que, básicamente, cuando yo haga la primera pieza de código, que va a hacer algo como esto: request query.; 5 seconds later when the request is done; console.log; cuando el segundo ejecuta una: request query; console.log; work on the query;
Azeirah
1
@JohnGalt el sql se ejecuta en un hilo diferente. Pero, por supuesto, eso depende de la implementación del controlador SQL que utilice. El controlador debe generar un nuevo hilo, conectarse a mysql y ejecutar la consulta. Una vez hecho esto, publique el resultado en la cola de eventos y Node llamará a la devolución de llamada.
Salvatorelab
44
¿No es posible que el ejemplo asíncrono genere lo mismo que el n. ° 1? Como por ejemplo, database.querytermina tan rápido que para cuando llegamos a console.logla tarea ya está hecha.
greatwolf
2
@TheBronx si console.log("Next line");en el ejemplo 2 estaba dentro de la función anónima, así que justo después console.log("query finished");, eso significaría que se imprimiría "Next Line" DESPUÉS de "consulta finalizada" ¿verdad? Por lo tanto, si tengo todo de forma anidada, todo se ejecutaría de forma sincrónica, por lo que no tendría que preocuparme por usar versiones sincrónicas de ciertas funciones. ¿Estoy correcto en mi entendimiento?
Abdul
44
Respuesta corta : Sí @Abdul, tienes razón. Respuesta larga : las funciones de anidamiento (devoluciones de llamada) son la forma de hacer las cosas de forma secuencial, "una tras otra". Pero eso no es "sincrónico" técnicamente. La función anónima aún se ejecuta "cuando la operación de bloqueo ha finalizado", o en otras palabras, "asincrónicamente". Node.js podría ejecutar otras funciones mientras se lleva a cabo esa operación de bloqueo. Las funciones permanecen asíncronas, es solo que las estás encadenando. Las funciones de sincronización bloquean la ejecución, esa es la clave.
Salvatorelab
75

La diferencia entre estos dos enfoques es la siguiente:

Modo sincrónico: espera a que se complete cada operación, después de eso solo ejecuta la siguiente operación. Para su consulta: el console.log()comando no se ejecutará hasta & a menos que la consulta haya terminado de ejecutarse para obtener todo el resultado de la base de datos.

Manera asincrónica: nunca espera a que se complete cada operación, sino que ejecuta todas las operaciones solo en el primer GO. El resultado de cada operación se manejará una vez que el resultado esté disponible. Para su consulta: el console.log()comando se ejecutará poco después del Database.Query()método. Mientras la consulta de la base de datos se ejecuta en segundo plano y carga el resultado una vez que finaliza la recuperación de los datos.

Casos de uso

  1. Si sus operaciones no están haciendo un trabajo muy pesado como consultar grandes datos desde la base de datos, continúe con la forma síncrona o asíncrona.

  2. De forma asincrónica, puede mostrar algunos indicadores de progreso al usuario, mientras que en segundo plano puede continuar con sus trabajos pesados. Este es un escenario ideal para aplicaciones GUI.

Santosh Panda
fuente
2
¿Eso significa que db.query (cmd, callback) se ejecuta simultáneamente (como en los subprocesos)? ¿Están corriendo al mismo tiempo?
Charlie Parker
En su segundo ejemplo, ¿hay alguna posibilidad de que la consulta finalice tan rápido que luego llame primero a la devolución de llamada, antes console.log?
Fahmi
@Fahmi teóricamente sí, prácticamente imposible
Leo Messi el
24

Esto se aclararía un poco si agrega una línea a ambos ejemplos:

var result = database.query("SELECT * FROM hugetable");
console.log(result.length);
console.log("Hello World");

El segundo:

database.query("SELECT * FROM hugetable", function(rows) {
   var result = rows;
   console.log(result.length);
});
console.log("Hello World");

Intente ejecutar estos, y notará que el primer ejemplo (sincrónico), el resultado.length se imprimirá ANTES de la línea 'Hola Mundo'. En el segundo ejemplo (el asíncrono), el resultado. La longitud (muy probablemente) se imprimirá DESPUÉS de la línea "Hola Mundo".

Esto se debe a que en el segundo ejemplo, database.queryse ejecuta de forma asíncrona en segundo plano, y el script continúa de inmediato con el "Hello World". El console.log(result.length)solo se ejecuta cuando la consulta de la base de datos se ha completado.

Martijn
fuente
1
usted dice: el resultado. la longitud se imprimirá (muy probablemente) DESPUÉS de la línea "Hola Mundo". .... ¿por qué sería eso "lo más probable"? Creo que siempre se imprime después de la salida de console.log. Gracias por la aclaración :)
humanityANDpeace
9
@humanityANDpeace: ese es el punto completo del acceso asincrónico: no sabes cuándo se hará. Tal vez sea una base de datos absurdamente rápido, y los retornos de consulta de base de datos, incluso antes de Javascript llega a la línea "Hello World" ...
Martijn
19

Primero, me doy cuenta de que llego tarde a responder esta pregunta.

Antes de analizar síncrono y asíncrono, veamos brevemente cómo se ejecutan los programas.

En el caso síncrono , cada declaración se completa antes de que se ejecute la siguiente. En este caso, el programa se evalúa exactamente en el orden de las declaraciones.

Así es como funciona asincrónico en JavaScript. Hay dos partes en el motor de JavaScript, una parte que mira el código y pone en cola las operaciones y otra que procesa la cola. El procesamiento de la cola ocurre en un hilo, es por eso que solo puede ocurrir una operación a la vez.

Cuando se ve una operación asincrónica (como la segunda consulta de la base de datos), el código se analiza y la operación se coloca en la cola, pero en este caso se registra una devolución de llamada para ejecutarse cuando se completa esta operación. La cola puede tener muchas operaciones en ella. La operación al frente de la cola se procesa y se elimina de la cola. Una vez que se procesa la operación para la consulta de la base de datos, la solicitud se envía a la base de datos y cuando se completa la devolución de llamada se ejecutará al finalizar. En este momento, el procesador de cola que ha "manejado" la operación se mueve en la siguiente operación, en este caso

    console.log("Hello World"); 

La consulta de la base de datos todavía se está procesando, pero la operación console.log está al frente de la cola y se procesa. Esta es una operación síncrona que se ejecuta de inmediato, lo que resulta inmediatamente en la salida "Hello World". Algún tiempo después, la operación de la base de datos se completa, solo entonces se llama y procesa la devolución de llamada registrada con la consulta, estableciendo el valor del resultado variable en filas.

Es posible que una operación asincrónica dé como resultado otra operación asincrónica, esta segunda operación se colocará en la cola y cuando llegue al frente de la cola se procesará. Llamar a la devolución de llamada registrada con una operación asincrónica es cómo el tiempo de ejecución de JavaScript devuelve el resultado de la operación cuando se realiza.

Un método simple para saber qué operación de JavaScript es asíncrona es observar si requiere una devolución de llamada: la devolución de llamada es el código que se ejecutará cuando se complete la primera operación. En los dos ejemplos en la pregunta, podemos ver que solo el segundo caso tiene una devolución de llamada, por lo que es la operación asincrónica de los dos. No siempre es así debido a los diferentes estilos de manejo del resultado de una operación asincrónica.

Para obtener más información, lea sobre las promesas. Las promesas son otra forma de manejar el resultado de una operación asincrónica. Lo bueno de las promesas es que el estilo de codificación se parece más a un código síncrono.

Muchas bibliotecas, como el nodo 'fs', proporcionan estilos sincrónicos y asincrónicos para algunas operaciones. En los casos en que la operación no toma mucho tiempo y no se usa mucho, como en el caso de leer un archivo de configuración, la operación de estilo síncrono dará como resultado un código que es más fácil de leer.

Arrendajo
fuente
6

En el caso sincrónico, el comando console.log no se ejecuta hasta que la consulta SQL haya terminado de ejecutarse.

En el caso asíncrono, el comando console.log se ejecutará directamente. El resultado de la consulta será almacenado por la función de "devolución de llamada" en algún momento posterior.

relacionado
fuente
1
¿Pero en realidad se les llama simultáneamente? Lo que me confunde es, en código asíncrono, ¿se está ejecutando el código real al mismo tiempo en paralelo?
Charlie Parker
Esto depende del procesador (¿es multinúcleo?) Y del sistema operativo. Ver en.wikipedia.org/wiki/Multithreading_(software)#Multithreading
relacionado
4

La principal diferencia es con la programación asincrónica, de lo contrario no se detiene la ejecución. Puede continuar ejecutando otro código mientras se realiza la 'solicitud'.

thebreiflabb
fuente
2

La función hace que el segundo sea asíncrono.

El primero obliga al programa a esperar a que cada línea termine de ejecutarse antes de que el siguiente pueda continuar. El segundo permite que cada línea se ejecute juntas (e independientemente) a la vez.

Los lenguajes y marcos (js, node.js) que permiten la asincronía o la concurrencia son excelentes para cosas que requieren transmisión en tiempo real (por ejemplo, chat, aplicaciones de archivo).

Anton Chan
fuente
0

Programación de sincronización

Los lenguajes de programación como C, C #, Java son programación de sincronización, cualquier cosa que escriba se ejecutará en el orden de su escritura.

-GET DATA FROM SQL.
//Suppose fetching data take 500 msec

-PERFORM SOME OTHER FUNCTION.
//Performing some function other will take 100 msec, but execution of other 
//task start only when fetching of sql data done (i.e some other function 
//can execute only after first in process job finishes).

-TOTAL TIME OF EXECUTION IS ALWAYS GREATER THAN (500 + 100 + processing time) 
msec

Asíncrono

NodeJs presenta una función asíncrona, no es de naturaleza de bloqueo, supongamos que en cualquier tarea de E / S que esté tomando tiempo (buscar, escribir, leer), nodejs no se mantendrá inactivo y esperará a que la tarea finalice, ' Comenzaré a ejecutar las siguientes tareas en la cola, y cada vez que se complete esa tarea, notificará mediante devolución de llamada. El siguiente ejemplo ayudará:

//Nodejs uses callback pattern to describe functions.
//Please read callback pattern to understand this example

//Suppose following function (I/O involved) took 500 msec
function timeConsumingFunction(params, callback){
  //GET DATA FROM SQL
  getDataFromSql(params, function(error, results){
    if(error){
      callback(error);
    }
    else{
      callback(null, results);
    }
  })
}

//Suppose following function is non-blocking and took 100 msec
function someOtherTask(){
  //some other task
  console.log('Some Task 1');
  console.log('Some Task 2');
}

console.log('Execution Start');

//Start With this function
timeConsumingFunction(params, function(error, results){
    if(error){
      console.log('Error')
    }
    else{
      console.log('Successfull'); 
    }
  })

//As (suppose) timeConsumingFunction took 500 msec, 
//As NodeJs is non-blocking, rather than remain idle for 500 msec, it will start 
//execute following function immediately
someOtherTask();

En resumen, la salida es como:

Execution Start
//Roughly after 105 msec (5 msec it'll take in processing)
Some Task 1
Some Task 2
//Roughly After 510 msec
Error/Successful //depends on success and failure of DB function execution

La diferencia es clara cuando la sincronización definitivamente tomará más de 600 (500 + 100 + tiempo de procesamiento) ms, asíncrono ahorra tiempo.

Neeraj Bansal
fuente
0

Las funciones síncronas están bloqueando mientras que las funciones asíncronas no. En funciones síncronas, las declaraciones se completan antes de que se ejecute la siguiente. En este caso, el programa se evalúa exactamente en el orden de las declaraciones y la ejecución del programa se detiene si una de las declaraciones lleva mucho tiempo.

Las funciones asincrónicas generalmente aceptan una devolución de llamada como parámetro y la ejecución continúa en la siguiente línea inmediatamente después de invocar la función asincrónica. La devolución de llamada solo se invoca cuando la operación asincrónica se completa y la pila de llamadas está vacía. Las operaciones pesadas, como cargar datos desde un servidor web o consultar una base de datos, se deben realizar de forma asincrónica para que el hilo principal pueda continuar ejecutando otras operaciones en lugar de bloquear hasta que se complete esa larga operación (en el caso de los navegadores, la IU se congelará) .

Orginal Publicado en Github: Enlace


fuente
0

Programación asincrónica en JS:

Sincrónico

  • Detiene la ejecución de más código hasta que se haga esto.
  • Debido a que esto detiene la ejecución posterior, el código síncrono se llama 'bloqueo'. Bloqueo en el sentido de que no se ejecutará ningún otro código.

Asincrónico

  • La ejecución de esto se difiere al bucle de eventos, esta es una construcción en una máquina virtual JS que ejecuta funciones asincrónicas (después de que la pila de funciones síncronas esté vacía).
  • El código asincrónico se llama no bloqueo porque no bloquea la ejecución de más código.

Ejemplo:

// This function is synchronous
function log(arg) {
    console.log(arg)
}

log(1);

// This function is asynchronous
setTimeout(() => {
    console.log(2)
}, 0);

log(3)

  • El ejemplo registra 1, 3, 2.
  • 2 se registra en último lugar porque está dentro de una función asincrónica que se ejecuta después de que la pila esté vacía.
Willem van der Veen
fuente