Node.js Generators e comparar com retornos de chamada

Neste tutorial, vamos aprender sobre Generatorse suas diferenças com retornos de chamada

O que são geradores?

Generatorse tornaram bastante famosos em Node.js nos últimos tempos e isso provavelmente se deve ao que são capazes de fazer.

  • Generators são execuções de funções que podem ser suspensas e retomadas posteriormente.
  • Generators são úteis ao executar conceitos como 'execução lenta'. Basicamente, isso significa que, ao suspender a execução e retomar à vontade, podemos extrair valores apenas quando necessário.

Generators têm os 2 métodos principais abaixo.

  1. Método de rendimento – O método yield é chamado em uma função para interromper a execução da função na linha específica onde o método yield é chamado.
  2. Próximo método – Este método é chamado a partir da aplicação principal para retomar a execução de uma função que possui um método yield. A execução da função continuará até o próximo método de rendimento ou até o final do método.

Vejamos um exemplo de como os geradores podem ser usados.

Em nosso exemplo, teremos uma função Add simples que adicionará 2 números, mas continuaremos interrompendo a execução do método em diferentes pontos para mostrar como os geradores podem ser usados.

Node.js Generators

function* Add(x) {
   yield x + 1;
   var y = yield(null);
   y = 6
   return x + y;
}

var gen = Add(5);

gen.next();

gen.next(); 

Explicação do código

  1. O primeiro passo é definir a “função” do nosso gerador. Observe que isso é feito adicionando um “*” à palavra-chave da função. Estamos então definindo uma função chamada Add que recebe um parâmetro de x.
  2. A palavra-chave yield é específica para geradores. Isso o torna uma construção poderosa para pausar uma função no meio de qualquer coisa. Então aqui, a execução da função será interrompida até invocarmos a função next(), o que será feito na Etapa 4. Neste ponto, o valor de x passará a ser 6 e a execução da função será interrompida.
  3. É aqui que primeiro chamamos a função geradora e enviamos o valor 5 para nossa função Add. Este valor será substituído no parâmetro x da nossa função Adicionar.
  4. Assim que chamarmos a função next(), a função Add() retomará a execução. Quando a próxima instrução var y= yield(null) for executada, a função Add() irá parar de executar novamente.
  5. Agora, depois de chamar a função next() novamente, as próximas instruções serão executadas e o valor combinado de x=5 e y=6 será adicionado e retornado.

Retornos de chamada vs. geradores

Generators são usados ​​para resolver o problema conhecido como callback hell. Às vezes, as funções de retorno de chamada ficam tão aninhadas durante o desenvolvimento de um aplicativo Node.js que fica muito complicado usar funções de retorno de chamada.

É aqui que os geradores são úteis. Um dos exemplos mais comuns disso é ao criar funções de timer.

Vejamos o exemplo abaixo de como os geradores podem ser úteis em retornos de chamada.

Nosso exemplo criará apenas uma função simples de atraso de tempo. Gostaríamos então de chamar esta função incorporando um atraso de 1000, 2000 e 3000 ms.

Passo 1) Defina nossa função de retorno de chamada com o código de atraso necessário.

Retornos de chamada vs. Generators

function Timedelay(ptime, callback) {

setTimeout(function() {
  
    callback("Pausing for " + ptime);
    
  }, time);
}

Explicação do código

  1. Aqui estamos criando uma função chamada Timedelay com um parâmetro chamado ptime. Isso levará o atraso necessário que queremos introduzir em nosso aplicativo.
  2. O próximo passo é apenas criar uma mensagem, que será exibida ao usuário informando que a aplicação ficará pausada por vários milissegundos.

Passo 2) Agora vamos dar uma olhada no código se estivéssemos incorporando retornos de chamada. Suponha que quiséssemos incorporar retornos de chamada com base no valor de 1000, 2000 e 3000 milissegundos. O código abaixo mostra como precisaríamos implementá-los usando retornos de chamada.

Retornos de chamada vs. Generators

Timedelay(1000, function(message) {
  
  console.log(msg);
  Timedelay(2000, function(message) {
    
    console.log(msg);
    Timedelay(3000, function(message) {
      
      console.log(msg);
  })
  })
})

Explicação do código

  1. Estamos chamando Timedelay como um retorno de chamada com 1000 como valor.
  2. Em seguida, queremos chamar a função Timedelay novamente com 2000 como valor.
  3. Finalmente, queremos chamar a função Timedelay novamente com 3000 como valor.

No código acima, você pode ver que fica mais confuso, pois queremos começar a chamar a função várias vezes.

Passo 3) Agora vamos ver como implementar o mesmo código usando geradores. No código abaixo você pode ver como se tornou simples implementar a função Timedelay usando geradores.

Retornos de chamada vs. Generators

function* Messages() {
  console,log(yield(Timedelay(1000, function(){})));
  console,log(yield(Timedelay(2000, function(){})));
  console,log(yield(Timedelay(3000, function(){})));
}

Explicação do código

  1. Estamos primeiro definindo uma função geradora que será usada para chamar nossa função Timedelay.
  2. Estamos chamando a função Yield junto com a função Timedelay com 1000 como valor do parâmetro.
  3. Em seguida, chamaremos a função Yield junto com a função Timedelay com 2000 como valor do parâmetro.
  4. Finalmente, estamos chamando a função Yield junto com a função Timedelay com 3000 como valor do parâmetro.

Resumo

Generators também pode ser usado para aliviar os problemas com retornos de chamada aninhados e ajudar a remover o que é conhecido como inferno de retorno de chamada. Generators são usados ​​para interromper o processamento de uma função. Isso é conseguido usando o método 'yield' na função assíncrona.