Skip to content

Instantly share code, notes, and snippets.

@luizamboni
Last active June 12, 2017 22:07
Show Gist options
  • Save luizamboni/1aca345a0d92bebaed6a1b36a9b4a298 to your computer and use it in GitHub Desktop.
Save luizamboni/1aca345a0d92bebaed6a1b36a9b4a298 to your computer and use it in GitHub Desktop.
node workshop

NodeJs

Assincronismo

Tarefas de IO em NodeJs são por padrão assíncronas, ou seja: o fluxo principal não fica em espera do retorno destas tarefas.

Callbacks

  const rows

  fs.readFile('data.csv', (err, data) => {
    rows = data
  })

Como a rotina principal não espera o retorno para atribuir a uma variável algum valor, é necessário o uso de um callback ao final da operação, que se encarregara de efetuar as ações necessárias, quando o recurso estiver disponível.

Quais os problemas da abordagem assincrona baseada em callbacks ?

  function readJSON(filename, callback){
    fs.readFile(filename, 'utf8', function (err, res){
      if (err) return callback(err)
      try {
        callback(null, JSON.parse(res))
      } catch (ex) {
        callback(ex)
      }
    })
  }
  • legibilidade muito ruim
  • várias checagens de erros no código
  • fora dos controles de fluxo convencionais
  • não retorna valores, as variáveis necessitam ser referenciadas dentro do callback para fazer "assign"

Promises

Promise é um objeto usado para processamento assíncrono. Um Promise (de "promessa") representa um valor que pode estar disponível agora, no futuro ou nunca...

Um Promise está um destes estados:

  • pending (pendente): Estado inicial, que não foi realizada nem rejeitada.
  • fulfilled (realizada): sucesso na operação.
  • rejected (rejeitado): falha na operação.
  • settled (estabelecida): Que foi realizada ou rejeitada.
 function readJSON(filename) {
   return new Promise((resolve, reject) => {
     fs.readFile(filename, 'utf8', (err, res) => {
       if (err) {
         reject(err)
         return
       }
       try {
         resolve( JSON.parse(res) )
       } catch (ex) {
         reject(ex)
       }
     })
   })
 }
 
 // calbacks here
 let products 
 readJSON("producs.json")
 .then( json => { // if end with success
   products = json
 })
 .catch(err => { // if end with fail
   console.error(err)
 })

Promisses podem ser encadeadas de maneira mais legível do que callbacks e o tratamento de errors pode ser feito em um único ponto, para uma cadeia de promisses.

  readJSON("producs.json")
  .then(json => { // if end with success
    return otherPromisseFunction(json)
  })
  .then(json => { // if 2nd end with success
    return andAnotherPromisseFunction(json)
  })
  .catch(err => { // if any promisse in chain fail
    console.error(err)
  })

Quais os problemas da abordagem assincrona baseada em Promisses ?

Houve uma melhora na legibilidade e no tratamento de erros, e Promises também retornam valores, que podem ser associados a variáveis fora do escopo sem que haja necessidade da promise instaciá-la ou referenciá-la.

  • fora dos controles de fluxo convencionais

Yield

Yield é uma palavra reservada que define pontos de retorno em uma function generator. A tradução de yield seria entrega, fornece, provê, isso ajuda a entender um pouco mais o seu propósito.

  function* foo() {
    const index = 0;
    while (index <= 2)
      yield index++;
  }
  const iterator = foo();
  console.log(iterator.next()); // { value: 0, done: false }
  console.log(iterator.next()); // { value: 1, done: false }
  console.log(iterator.next()); // { value: 2, done: false }
  console.log(iterator.next()); // { value: undefined, done: true }

A cada chamada de next() o próximo yield é retornado

functionGenerator

São funções que podem ser pausadas e retornadas de onde foram pausadas.

  function* foo() {
    let index = 0;
    while (index <= 3){
      yield index++;
      if(index === 2)
        return "valor"
    }
  }
  const iterator = foo();
  console.log(iterator.next()); // { value: 0, done: false }
  console.log(iterator.next()); // { value: 1, done: false }
  console.log(iterator.next()); // { value: 2, done: false }
  console.log(iterator.next()); // { value: "valor", done: true }
  console.log(iterator.next()); // { value: undefined, done: true }

A palavra chave yield indica pontos de pausa e retorno da função, mas se houver um return a função terminará quando o alcançar.

É possivel usar o yield para passagem de parâmetros

  function* logGenerator() {
    console.log(yield);
    console.log(yield);
    console.log(yield);
  }

  const gen = logGenerator();

  // the first call of next executes from the start of the function
  // until the first yield statement
  gen.next(); 
  gen.next('pretzel'); // pretzel
  gen.next('california'); // california
  gen.next('mayonnaise'); // mayonnaise

yield como controle de assincronia

Com libs como co é possivel controlar promisses e generators através da palavra-chave `yield```

  co(function*() {
   const json = yield readJSON("producs.json")
  })

muito mais legível, e também pode ser usado com coleções

Como array

  const [ products, users ] = yield [
    readJSON("producs.json"),
    readJSON("users.json"),
  ]

Ou como object

  const { products, users } = yield {
    products: readJSON("producs.json"),
    users: readJSON("users.json"),
  }

Tests

Vantagens

  • menos errors
  • força o desenvolvedor a planejar melhor a sua api
  • refatoração

Palavras chaves

TDD - Test Driven Development BDD - Behavior Driven Development

libs

  • mocha (mocha-co)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment