Qual è la differenza tra la programmazione sincrona e asincrona (in node.js)


189

Ho letto nodebeginner E mi sono imbattuto nei seguenti due pezzi di codice.

Il primo:

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

Il secondo:

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

Ottengo quello che dovrebbero fare, interrogano il database per recuperare la risposta alla query. E poi console.log('Hello world').

Il primo è presumibilmente codice sincrono. E il secondo è il codice asincrono.

La differenza tra i due pezzi è molto vaga per me. Quale sarebbe l'output?

Googling sulla programmazione asincrona non mi ha aiutato neanche.


41
Sconosciuto che non hai trovato nulla con Google, è un argomento piuttosto grande. Nella programmazione sincrona, ogni passaggio viene eseguito uno dopo il completamento dell'esecuzione del precedente. In modalità asincrona, il passaggio 2 verrà eseguito anche se il passaggio 1 non è terminato. La funzione che vedi definita nel secondo esempio si chiama funzione callBack e verrà eseguita non appena verrà restituito il risultato dal database, che probabilmente avverrà dopo l'esecuzione di console.log.
Laurent S.

7
@Bartdude C'era molto sulla programmazione asincrona, ma nessuna spiegazione in qualche modo semplice su cosa sia e cosa significhi in pratica.
Azeirah,

1
@GabrielLlamas Perché dovremmo evitare le funzioni sincrone?
Charlie Parker,

3
@CharlieParker Perché bloccano il loop degli eventi e perdi tutti i vantaggi di un modello I / O con evento asincrono. E perché è una cattiva pratica. Pensaci in questo modo: se non stai usando funzioni asincrone, perché stai usando Node.js?
Gabriel Llamas,

1
@GabrielLlamas, se sto eseguendo una query INSERT e dopo voglio usare l'ultimo ID inserito database.query(), allora dovrei chiamarlo in modo sincrono, giusto? o quale dovrebbe essere l'approccio? (Questa domanda che ho da molto tempo)
San

Risposte:


225

La differenza è che nel primo esempio , il programma si bloccherà nella prima riga. La riga successiva ( console.log) dovrà attendere.

Nel secondo esempio , console.logverrà eseguito MENTRE la query è in fase di elaborazione. Cioè, la query verrà elaborata in background, mentre il tuo programma sta facendo altre cose e, una volta che i dati della query saranno pronti, farai tutto ciò che desideri.

Quindi, in breve: il primo esempio si bloccherà, mentre il secondo no.

L'output dei seguenti due esempi:

// 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");

Sarebbe:

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

Nota
Mentre il nodo stesso è a thread singolo , ci sono alcune attività che possono essere eseguite in parallelo. Ad esempio, le operazioni del file system si verificano in un processo diverso.

Ecco perché Node può eseguire operazioni asincrone: un thread sta eseguendo operazioni sul file system, mentre il thread Node principale continua a eseguire il tuo codice javascript. In un server guidato da eventi come Node, il thread del file system notifica al thread Node principale alcuni eventi quali completamento, errore o avanzamento, insieme a tutti i dati associati a tale evento (come il risultato di una query del database o un errore messaggio) e il thread del nodo principale decide cosa fare con quei dati.

Puoi leggere ulteriori informazioni qui: Come funziona il modello IO non bloccante a thread singolo in Node.js


9
Quindi, fondamentalmente, quando eseguo il primo pezzo di codice, farà qualcosa del genere request query.; 5 seconds later when the request is done; console.log:; quando il secondo viene eseguito una: request query; console.log; work on the query;
Azeirah,

1
@JohnGalt the sql gira su un thread diverso. Ma ovviamente ciò dipende dall'implementazione del driver sql che usi. Il driver dovrebbe generare un nuovo thread, connettersi a mysql ed eseguire la query. Una volta fatto, pubblica il risultato nella coda degli eventi e Node chiamerà il callback.
Salvatorelab,

4
Non è possibile che l'esempio asincrono produca la stessa cosa del numero 1? Come ad esempio, database.queryfinisce così in fretta che quando raggiungiamo console.logl'attività è già terminata .
greatwolf il

2
@TheBronx se console.log("Next line");nell'esempio 2 si trovasse all'interno della funzione anonima, quindi subito dopo console.log("query finished");, ciò significherebbe che "Next Line" verrebbe stampata DOPO "query terminata", giusto? Quindi, se avessi tutto in modo annidato, tutto sarebbe eseguito in modo sincrono, quindi non avrei bisogno di preoccuparmi di usare versioni sincrone di determinate funzioni. Sono corretto nella mia comprensione?
Abdul

4
Risposta breve : Sì @Abdul, hai ragione. Risposta lunga : le funzioni di nidificazione (callback) sono il modo di fare le cose in sequenza, "una dopo l'altra". Ma questo non è "sincrono" tecnicamente. La funzione anonima viene comunque eseguita "al termine dell'operazione di blocco" o, in altre parole, "in modo asincrono". Node.js potrebbe eseguire altre funzioni mentre è in corso l'operazione di blocco. Le funzioni rimangono asincrone, è solo che le stai concatenando. La funzione di sincronizzazione blocca l'esecuzione, questa è la chiave.
Salvatorelab

75

La differenza tra questi due approcci è la seguente:

Modo sincrono: attende il completamento di ciascuna operazione, dopodiché esegue solo l'operazione successiva. Per la tua query: il console.log()comando non verrà eseguito fino a quando la query non avrà terminato l'esecuzione per ottenere tutti i risultati dal database.

Modo asincrono: non attende mai il completamento di ciascuna operazione, ma esegue tutte le operazioni solo nel primo GO. Il risultato di ciascuna operazione verrà gestito quando il risultato sarà disponibile. Per la tua query: il console.log()comando verrà eseguito subito dopo il Database.Query()metodo. Mentre la query del database viene eseguita in background e carica il risultato al termine del recupero dei dati.

Casi d'uso

  1. Se le tue operazioni non eseguono operazioni di sollevamento molto pesanti come la query di enormi dati dal DB, procedi in modo sincrono, altrimenti in modo asincrono.

  2. In modo asincrono puoi mostrare all'utente un indicatore di avanzamento mentre in background puoi continuare con i tuoi lavori pesanti. Questo è uno scenario ideale per le app della GUI.


2
Ciò significa che db.query (cmd, callback) è in esecuzione contemporaneamente (come nei thread)? Stanno correndo allo stesso tempo?
Charlie Parker,

Nel suo secondo esempio, c'è qualche possibilità che la query finisca così velocemente da chiamare prima il callback prima console.log?
Fahmi,

@Fahmi teoricamente sì, praticamente impossibile
Leo Messi il

24

Ciò diventerebbe un po 'più chiaro se aggiungi una riga ad entrambi gli esempi:

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

Il secondo:

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

Prova a eseguirli e noterai che il primo esempio (sincrono), il risultato.lunghezza, verrà stampato PRIMA della riga "Hello World". Nel secondo esempio (asincrono), il risultato.lunghezza sarà (molto probabilmente) stampato DOPO la riga "Hello World".

Questo perché nel secondo esempio, database.queryviene eseguito in modo asincrono in background e lo script continua immediatamente con "Hello World". L' console.log(result.length)viene eseguito solo quando la query di database è stata completata.


1
tu dici: il risultato.lunghezza sarà (molto probabilmente) stampato DOPO la riga "Hello World". .... perché sarebbe solo "molto probabile"? Penso che sia sempre stampato dopo l'output console.log. Grazie per il chiarimento :)
umanità e

9
@humanityANDpeace: questo è l'intero punto di accesso asincrono: non sai quando sarà fatto. Forse è un database assurdamente veloce e la query del database ritorna anche prima che Javascript arrivi alla riga "Hello World" ...
Martijn,

19

Innanzitutto, mi rendo conto di essere in ritardo nel rispondere a questa domanda.

Prima di discutere di sincrono e asincrono, esaminiamo brevemente come funzionano i programmi.

Nel caso sincrono , ogni istruzione viene completata prima dell'esecuzione dell'istruzione successiva. In questo caso il programma viene valutato esattamente nell'ordine delle dichiarazioni.

Ecco come funziona asincrono in JavaScript. Esistono due parti nel motore JavaScript, una parte che esamina il codice e accoda le operazioni e un'altra che elabora la coda. L'elaborazione della coda avviene in un thread, ecco perché può succedere solo un'operazione alla volta.

Quando viene visualizzata un'operazione asincrona (come la seconda query del database), il codice viene analizzato e l'operazione viene inserita nella coda, ma in questo caso viene registrato un callback da eseguire al termine dell'operazione. La coda potrebbe contenere già molte operazioni. L'operazione nella parte anteriore della coda viene elaborata e rimossa dalla coda. Una volta elaborata l'operazione per la query del database, la richiesta viene inviata al database e una volta completato il callback verrà eseguito al completamento. A questo punto, il processore di coda che ha "gestito" l'operazione passa all'operazione successiva, in questo caso

    console.log("Hello World"); 

La query del database è ancora in fase di elaborazione, ma l'operazione console.log si trova nella parte anteriore della coda e viene elaborata. Essendo un'operazione sincrona viene eseguita immediatamente con conseguente risultato "Hello World". Qualche tempo dopo, l'operazione del database viene completata, solo allora viene richiamata ed elaborata la richiamata registrata con la query, impostando il valore del risultato della variabile su righe.

È possibile che un'operazione asincrona provocherà un'altra operazione asincrona, questa seconda operazione verrà inserita nella coda e quando verrà in primo piano verrà elaborata. La chiamata del callback registrato con un'operazione asincrona è il modo in cui il runtime JavaScript restituisce il risultato dell'operazione al termine.

Un metodo semplice per sapere quale operazione JavaScript è asincrona è notare se richiede un callback: il callback è il codice che verrà eseguito al termine della prima operazione. Nei due esempi nella domanda, possiamo vedere che solo il secondo caso ha un callback, quindi è l'operazione asincrona dei due. Non è sempre il caso a causa dei diversi stili di gestione del risultato di un'operazione asincrona.

Per saperne di più, leggi le promesse. Le promesse sono un altro modo in cui è possibile gestire il risultato di un'operazione asincrona. La cosa bella delle promesse è che lo stile di codifica sembra più un codice sincrono.

Molte librerie come il nodo 'fs' forniscono stili sia sincroni che asincroni per alcune operazioni. Nei casi in cui l'operazione non richiede molto tempo e non viene utilizzata molto - come nel caso della lettura di un file di configurazione - l'operazione di stile sincrono si tradurrà in codice più facile da leggere.


6

Nel caso sincrono, il comando console.log non viene eseguito fino al termine dell'esecuzione della query SQL.

Nel caso asincrono, il comando console.log verrà eseguito direttamente. Il risultato della query verrà quindi memorizzato dalla funzione "callback" qualche tempo dopo.


1
Ma vengono effettivamente chiamati contemporaneamente? La cosa che mi confonde è, in codice asincrono, che il codice effettivo venga eseguito contemporaneamente in parallelo?
Charlie Parker,

Questo dipende dal processore (è multi-core?) E dal sistema operativo. Vedi en.wikipedia.org/wiki/Multithreading_(software)#Multithreading
relativo al

4

La differenza principale è con la programmazione asincrona, altrimenti non si interrompe l'esecuzione. È possibile continuare a eseguire altro codice mentre viene effettuata la "richiesta".


2

La funzione rende la seconda asincrona.

Il primo impone al programma di attendere che ogni riga termini l'esecuzione prima che il successivo possa continuare. La seconda consente a ciascuna linea di funzionare insieme (e indipendentemente) contemporaneamente.

I linguaggi e i framework (js, node.js) che consentono asincrono o concorrenza sono ottimi per le cose che richiedono la trasmissione in tempo reale (es. Chat, applicazioni stock).


0

Sincronizza programmazione

I linguaggi di programmazione come C, C #, Java sono la sincronizzazione della programmazione, tutto ciò che si scrive verrà eseguito in ordine di scrittura.

-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

Async

NodeJs viene fornito con la funzione asincrona, è di natura non bloccante, supponiamo in qualsiasi attività di I / O che richiede tempo (recupero, scrittura, lettura), nodejs non rimarrà inattivo e aspetterà che l'attività finisca, è ' Inizierò a eseguire le attività successive nella coda e ogni volta che il completamento dell'attività verrà notificato tramite callback. Il seguente esempio aiuterà:

//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();

In breve, l'output è il seguente:

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 differenza è chiara in cui la sincronizzazione richiederà sicuramente più di 600 (500 + 100 + tempo di elaborazione) msec, asincrona consente di risparmiare tempo.


0

Le funzioni sincrone stanno bloccando, mentre le funzioni asincrone non lo sono. Nelle funzioni sincrone, le istruzioni vengono completate prima dell'esecuzione dell'istruzione successiva. In questo caso, il programma viene valutato esattamente nell'ordine delle istruzioni e l'esecuzione del programma viene messa in pausa se una delle istruzioni impiega molto tempo.

Le funzioni asincrone di solito accettano un callback come parametro e l'esecuzione continua sulla riga successiva immediatamente dopo che è stata invocata la funzione asincrona. Il callback viene richiamato solo quando l'operazione asincrona è completa e lo stack di chiamate è vuoto. Operazioni pesanti come il caricamento di dati da un server Web o l'interrogazione di un database devono essere eseguite in modo asincrono in modo che il thread principale possa continuare ad eseguire altre operazioni invece di bloccare fino al completamento di quella lunga operazione (nel caso dei browser, l'interfaccia utente si bloccherà) .

Originale pubblicato su Github: Link


0

Programmazione asincrona in JS:

Sincrono

  • Interrompe l'esecuzione di ulteriore codice fino a quando ciò non viene eseguito.
  • Perché questo arresto di ulteriori esecuzioni, il codice sincrono si chiama 'blocco'. Blocco nel senso che nessun altro codice verrà eseguito.

asincrono

  • L'esecuzione di questo è rinviata al loop degli eventi, questo è un costrutto in una macchina virtuale JS che esegue funzioni asincrone (dopo che lo stack di funzioni sincrone è vuoto).
  • Il codice asincrono viene chiamato non bloccante perché non blocca l'esecuzione di ulteriore codice.

Esempio:

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

log(1);

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

log(3)

  • L'esempio registra 1, 3, 2.
  • 2 viene registrato per ultimo perché si trova all'interno di una funzione asincrona che viene eseguita dopo che lo stack è vuoto.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.