Qual é a diferença entre programação síncrona e assíncrona (em node.js)

189

Eu tenho lido nodebeginner e me deparei com os dois seguintes pedaços de código.

O primeiro:

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

O segundo:

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

Eu entendo o que eles devem fazer, eles consultam o banco de dados para recuperar a resposta para a consulta. E então console.log('Hello world').

O primeiro é um código supostamente síncrono. E o segundo é um código assíncrono.

A diferença entre as duas peças é muito vaga para mim. Qual seria a saída?

Pesquisando em programação assíncrona também não me ajudou.

Azeirah
fonte
41
Estranho que você não encontrou nada com o google, é um assunto bastante grande. Na programação síncrona, cada etapa é executada uma após a execução anterior da anterior. No modo assíncrono, a etapa 2 será executada mesmo que a etapa 1 não seja concluída. A função que você vê definida no seu segundo exemplo é chamada de função callBack e será executada assim que o resultado do banco de dados for retornado, o que provavelmente ocorrerá após a execução do console.log.
Laurent S.
7
@ Bartdude Havia muita programação assíncrona, mas nenhuma explicação simples sobre o que é e o que significa na prática.
Azeirah
1
@GabrielLlamas Por que devemos evitar funções síncronas?
Charlie Parker
3
@CharlieParker Porque eles bloqueiam o loop de eventos e você está perdendo todos os benefícios de um modelo de E / S com evento assíncrono. E porque é uma prática ruim. Pense da seguinte maneira: se você não está usando funções assíncronas, por que você está usando o Node.js.
Gabriel Llamas
1
@ GabrielLlamas, se estou executando uma consulta INSERT e quero usar o último ID inserido depois database.query(), devo chamá-lo de forma síncrona, certo? ou qual deve ser a abordagem? (Esta pergunta eu tenho há muito tempo) #
San

Respostas:

224

A diferença é que, no primeiro exemplo , o programa será bloqueado na primeira linha. A próxima linha ( console.log) terá que esperar.

No segundo exemplo , o console.logserá executado enquanto a consulta estiver sendo processada. Ou seja, a consulta será processada em segundo plano, enquanto o programa estiver fazendo outras coisas e, quando os dados da consulta estiverem prontos, você fará o que quiser com ele.

Então, em poucas palavras: o primeiro exemplo irá bloquear, enquanto o segundo não.

A saída dos dois exemplos a seguir:

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

Seria:

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

Nota
Enquanto o próprio nó é único , há algumas tarefas que podem ser executadas em paralelo. Por exemplo, as operações do sistema de arquivos ocorrem em um processo diferente.

É por isso que o Node pode executar operações assíncronas: um encadeamento realiza operações do sistema de arquivos, enquanto o encadeamento principal do Node continua executando seu código javascript. Em um servidor orientado a eventos como o Node, o encadeamento do sistema de arquivos notifica o encadeamento principal do Node de certos eventos, como conclusão, falha ou progresso, juntamente com quaisquer dados associados a esse evento (como resultado de uma consulta ao banco de dados ou erro) mensagem) e o encadeamento principal do Nó decide o que fazer com esses dados.

Você pode ler mais sobre isso aqui: Como o modelo de IO único e sem bloqueio de threads funciona no Node.js

Salvatorelab
fonte
9
Então, basicamente, quando eu executo o primeiro trecho de código, ele fará algo assim request query.; 5 seconds later when the request is done; console.log:; Quando o segundo executa uma: request query; console.log; work on the query;
Azeirah
1
@JohnGalt, o sql é executado em um thread diferente. Mas é claro que isso depende da implementação do driver sql que você usa. O driver deve gerar um novo thread, conectar-se ao mysql e executar a consulta. Depois de feito, publique o resultado na fila de eventos e o Node chamará o retorno de chamada.
Salvatorelab
4
Não é possível que o exemplo assíncrono produza a mesma coisa que o número 1? Por exemplo, database.querytermina tão rápido que, quando chegamos console.logà tarefa, já está pronto.
greatwolf
2
@TheBronx se console.log("Next line");no exemplo 2 estivesse dentro da função anônima, logo depois console.log("query finished");, isso significaria que "Next Line" seria impressa APÓS "consulta concluída", certo? Portanto, se eu tiver tudo de maneira aninhada, tudo será executado de maneira síncrona, portanto, não precisarei me preocupar em usar versões síncronas de certas funções. Estou correto no meu entendimento?
Abdul
4
Resposta curta : Sim @Abdul, você está certo. Resposta longa : funções de aninhamento (retornos de chamada) é a maneira de fazer as coisas sequencialmente, "uma após a outra". Mas isso não é tecnicamente "síncrono". A função anônima ainda é executada "quando a operação de bloqueio terminar" ou, em outras palavras, "de forma assíncrona". O Node.js pode executar outras funções enquanto essa operação de bloqueio está ocorrendo. As funções permanecem assíncronas, é só que você as está encadeando. As funções de sincronização bloqueiam a execução, essa é a chave.
Salvatorelab
74

A diferença entre essas duas abordagens é a seguinte:

Maneira síncrona: Aguarda a conclusão de cada operação, somente depois executa a próxima operação. Para sua consulta: O console.log()comando não será executado até & a menos que a consulta tenha terminado de executar para obter todo o resultado do Banco de Dados.

Maneira assíncrona: nunca espera que cada operação seja concluída, mas executa todas as operações apenas no primeiro GO. O resultado de cada operação será tratado assim que o resultado estiver disponível. Para sua consulta: O console.log()comando será executado logo após o Database.Query()método. Enquanto a consulta ao banco de dados é executada em segundo plano e carrega o resultado após a recuperação dos dados.

Casos de uso

  1. Se suas operações não estiverem sendo muito pesadas, como consultar grandes dados do banco de dados, vá em frente com a maneira síncrona ou a maneira assíncrona.

  2. De maneira assíncrona, você pode mostrar algum indicador de progresso ao usuário, enquanto em segundo plano, pode continuar com seus trabalhos pesados. Este é um cenário ideal para aplicativos da GUI.

Santosh Panda
fonte
2
Isso significa que o db.query (cmd, callback) está sendo executado simultaneamente (como nos threads)? Eles estão correndo ao mesmo tempo?
Charlie Parker
Em seu segundo exemplo, há alguma chance de a consulta terminar tão rápido que antes chama o retorno de chamada antes console.log?
Fahmi #
@Fahmi, teoricamente, sim, praticamente impossível #
Leo Messi
24

Isso ficaria um pouco mais claro se você adicionar uma linha aos dois exemplos:

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

O segundo:

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

Tente executá-los e você notará que o primeiro exemplo (síncrono), o resultado.length, será impresso ANTES da linha 'Hello World'. No segundo exemplo (o assíncrono), o result.length (provavelmente) será impresso DEPOIS da linha "Hello World".

Isso database.queryocorre porque, no segundo exemplo, ele é executado de forma assíncrona em segundo plano, e o script continua imediatamente com o "Hello World". O console.log(result.length)é executado somente quando a consulta ao banco de dados for concluída.

Martijn
fonte
1
você diz: o result.length (provavelmente) será impresso DEPOIS da linha "Hello World". .... por que isso seria apenas "mais provável"? Eu acho que é sempre impresso após a saída console.log. Obrigado pelo esclarecimento :)
humanidadeANDpeace
9
@ humanityANDpeace: esse é o ponto principal do acesso assíncrono: você não sabe quando isso será feito. Talvez seja um banco de dados absurdamente rápido, ea consulta de banco de dados retorna antes mesmo Javascript fica para a linha "Olá Mundo" ...
Martijn
19

Primeiro, percebo que estou atrasado em responder a essa pergunta.

Antes de discutirmos síncrono e assíncrono, vejamos brevemente como os programas são executados.

No caso síncrono , cada instrução é concluída antes da execução da próxima instrução. Nesse caso, o programa é avaliado exatamente na ordem das instruções.

É assim funciona assíncrono em JavaScript. Existem duas partes no mecanismo JavaScript, uma parte que analisa as operações de código e enfileiramento e outra que processa a fila. O processamento da fila ocorre em um encadeamento, é por isso que apenas uma operação pode acontecer por vez.

Quando uma operação assíncrona (como a segunda consulta ao banco de dados) é vista, o código é analisado e a operação é colocada na fila, mas, nesse caso, um retorno de chamada é registrado para ser executado quando essa operação é concluída. A fila já pode ter muitas operações. A operação na frente da fila é processada e removida da fila. Depois que a operação da consulta ao banco de dados é processada, a solicitação é enviada ao banco de dados e, quando concluída, o retorno de chamada será executado na conclusão. No momento, o processador de filas que "manipulou" a operação passa para a próxima operação - nesse caso

    console.log("Hello World"); 

A consulta ao banco de dados ainda está sendo processada, mas a operação console.log está na frente da fila e é processada. Sendo uma operação síncrona executada imediatamente, resultando imediatamente na saída "Hello World". Algum tempo depois, a operação do banco de dados é concluída, somente então o retorno de chamada registrado com a consulta é chamado e processado, configurando o valor do resultado da variável para linhas.

É possível que uma operação assíncrona resulte em outra operação assíncrona, essa segunda operação seja colocada na fila e, quando chegar à frente da fila, será processada. Chamar o retorno de chamada registrado com uma operação assíncrona é como o tempo de execução do JavaScript retorna o resultado da operação quando ela é concluída.

Um método simples de saber qual operação JavaScript é assíncrona é observar se é necessário um retorno de chamada - o retorno de chamada é o código que será executado quando a primeira operação for concluída. Nos dois exemplos da pergunta, podemos ver apenas o segundo caso com retorno de chamada, portanto, é a operação assíncrona dos dois. Nem sempre é o caso devido aos diferentes estilos de manipulação do resultado de uma operação assíncrona.

Para saber mais, leia sobre promessas. As promessas são outra maneira pela qual o resultado de uma operação assíncrona pode ser tratado. O bom das promessas é que o estilo de codificação parece mais com código síncrono.

Muitas bibliotecas, como o nó 'fs', fornecem estilos síncrono e assíncrono para algumas operações. Nos casos em que a operação não leva muito tempo e não é muito usada - como no caso de ler um arquivo de configuração - a operação de estilo síncrono resultará em um código mais fácil de ler.

Jay
fonte
6

No caso síncrono, o comando console.log não é executado até que a consulta SQL termine de executar.

No caso assíncrono, o comando console.log será executado diretamente. O resultado da consulta será armazenado pela função "retorno de chamada" algum tempo depois.

relacionado
fonte
1
Mas, na verdade, eles estão sendo chamados simultaneamente? O que me confunde é que, em código assíncrono, o código real está sendo executado ao mesmo tempo em paralelo?
Charlie Parker
Isso depende do processador (é multi-core?) E do sistema operacional. Veja en.wikipedia.org/wiki/Multithreading_(software)#Multithreading
relacionado em
4

A principal diferença está na programação assíncrona, caso contrário, você não interrompe a execução. Você pode continuar executando outro código enquanto a 'solicitação' estiver sendo feita.

thebreiflabb
fonte
2

A função torna o segundo assíncrono.

O primeiro força o programa a esperar que cada linha termine sua execução antes que o próximo possa continuar. O segundo permite que cada linha corra juntas (e independentemente) de uma só vez.

Idiomas e estruturas (js, node.js) que permitem assincronia ou simultaneidade são ótimos para coisas que exigem transmissão em tempo real (por exemplo, bate-papo, aplicativos de estoque).

Anton Chan
fonte
0

Programação de sincronização

Linguagens de programação como C, C #, Java são programação de sincronização, o que quer que você escreva será executado na ordem em que você escrever.

-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

Assíncrono

Os NodeJs apresentam um recurso assíncrono, não é de natureza bloqueadora, suponha que em qualquer tarefa de E / S que esteja demorando (buscando, gravando, lendo), o nodejs não permanecerá ocioso e aguardará a conclusão da tarefa, é ' Começamos a executar as próximas tarefas na fila e, sempre que essa tarefa demorada for concluída, ela será notificada usando o retorno de chamada. O exemplo a seguir ajudará:

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

Em suma, a saída é 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

É clara a diferença em que a sincronização definitivamente levará mais de 600 (500 + 100 + tempo de processamento) ms, o async economiza tempo.

Neeraj Bansal
fonte
0

Funções síncronas estão bloqueando enquanto funções assíncronas não estão. Nas funções síncronas, as instruções são concluídas antes da execução da próxima instrução. Nesse caso, o programa é avaliado exatamente na ordem das instruções e a execução do programa é interrompida se uma das instruções demorar muito tempo.

As funções assíncronas geralmente aceitam um retorno de chamada como parâmetro e a execução continua na próxima linha imediatamente após a chamada da função assíncrona. O retorno de chamada é chamado apenas quando a operação assíncrona estiver concluída e a pilha de chamadas estiver vazia. Operações pesadas, como carregar dados de um servidor Web ou consultar um banco de dados, devem ser executadas de forma assíncrona, para que o encadeamento principal possa continuar executando outras operações em vez de bloquear até que a operação seja concluída (no caso de navegadores, a interface do usuário congelará) .

Original publicado no Github: Link


fonte
0

Programação assíncrona em JS:

Síncrono

  • Pára a execução de mais códigos até que isso seja feito.
  • Por ser esta parada de execução adicional, o código síncrono é chamado de 'bloqueio'. Bloqueando no sentido de que nenhum outro código será executado.

Assíncrono

  • A execução disso é adiada para o loop de eventos, é uma construção em uma máquina virtual JS que executa funções assíncronas (depois que a pilha de funções síncronas fica vazia).
  • O código assíncrono é chamado sem bloqueio porque não impede a execução de mais códigos.

Exemplo:

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

log(1);

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

log(3)

  • O exemplo registra 1, 3, 2.
  • 2 é registrado por último porque está dentro de uma função assíncrona que é executada após a pilha estar vazia.
Willem van der Veen
fonte