Você não conhece

William Grasel

@willgmbr

github.com/willgm

Arquitetura não bloqueante

Callbacks??


  System.out.println("Step: 1");
  System.out.println("Step: 2");
  Thread.sleep(1000);
  System.out.println("Step: 3");

  console.log('Step: 1');
  setTimeout(function () {
    console.log('Step: 3');
  }, 1000)
  console.log('Step: 2');

Bloqueando seu NodeJS


  for (let i = 1; i<1000000000; i++) {
    // Vai levar 100 ~ 1000ms
  }

  const fs = require('fs');

  const contents = fs.readFileSync('myfile.txt','utf8');

  console.log('Hello Ruby', contents);

  const fs = require('fs');

  fs.readFile('myfile.txt','utf8', (err,contents) => {
    console.log('Hello NodeJS', contents);
  });

Window??

  • global
  • global.__filename
  • global.__dirname
  • global.process

Process attributes

  • process.pid
  • process.versions
  • process.argv
  • process.env

Process methods

  • process.uptime()
  • process.memoryUsage()
  • process.cwd()
  • process.exit()
  • process.on()

CommonJS


  const hello = require('world');

  const hello = require('world');

  exports.foo = function bar() {};

  const hello = require('world');

  exports.foo = function bar() {};

  module.exports = { myObj: 123 };

  const hello = require('world');

  exports.foo = function bar() {};

  module.exports = { myObj: 123 };

  global.module.exports = {}

global.module

  • module.exports
  • module.filename
  • module.id

Callback Hell =/


  fs.readdir(source, function (err, files) {
    if (err) {
      console.log('Error finding files: ' + err)
    } else {
      files.forEach(function (filename, fileIndex) {
        console.log(filename)
        gm(source + filename).size(function (err, values) {
          if (err) {
            console.log('Error identifying file size: ' + err)
          } else {
            console.log(filename + ' : ' + values)
            aspect = (values.width / values.height)
            widths.forEach(function (width, widthIndex) {
              height = Math.round(width / aspect)
              console.log('resizing ' + filename + 'to ' + height + 'x' + height)
              this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
                if (err) console.log('Error writing file: ' + err)
              })
            }.bind(this))
          }
        })
      })
    }
  })

Promises?


  remotedb.allDocs({  
    include_docs: true,
    attachments: true
  }).then(function (result) {
    var docs = result.rows;
    docs.forEach(function(element) {
      localdb.put(element.doc).then(function(response) {
        console.log("Pulled doc with id ",  element.doc._id);
      }).catch(function (err) {
        if (err.status == 409) {
          localdb.get(element.doc._id).then(function (resp) {
            localdb.remove(resp._id, resp._rev).then(function (resp) {
              // Lá vamos nós de novo....

Vertical é melhor


  remotedb.allDocs(...)
  .then( resultOfAllDocs => localdb.put(...) )
  .then( resultOfPut => localdb.get(...) )
  .then( resultOfGet => localdb.put(...) );

Múltiplas promises


  // Bora remover todas as linhas de um documento:
  db.allDocs({include_docs: true})
  .then( result => {  
    result.rows.forEach( row => {
      db.remove(row.doc);  
    });
  }).then(() => {
    // Terminou??
  });

  // Bora remover todas as linhas de um documento:
  db.allDocs({include_docs: true})
  .then( result => {  
    return Promise.all(result.rows.map( row => {
      return db.remove(row.doc);
    }));
  }).then( arrayDeResultados => {
    // Agora sim todas as linhas foram removidas!
  });

Caça fantasmas


  minhaPromise().then(() => {  
    throw new Error('Oooops!');
  }).catch( err => {
    console.log(err);
  });

Event Emitter


  const events  = require("events");
  const emitter = new events.EventEmitter();

  emitter.on("knock", () => {
    console.log("Who's there?");
  })

  emitter.on("knock", () => {
    console.log("Go away!");
  })

  emitter.emit("knock");

  const { EventEmitter } = require('events');

  class MyObject extend EventEmitter {
    foo() {
      this.emit('bar');
    }
  }

  const hello = new MyObject;

  hello.on('bar', () => console.log('wow'))
  hello.foo();

Outros métodos

  • emitter.listeners(eventName)
  • emitter.once(eventName, listener)
  • emitter.removeListener(eventName, listener)

Streams

  • Readable: apenas leitura
  • Writable: apenas escrita
  • Duplex: leitura e escrita de entrada e saída diferente
  • Transform: leitura e escrita de uma mesma entrada e saída

Node S2 Streams

  • HTTP requests e responses
  • Padrões de input/output
  • Leitura e escrita de arquivos

Streams de Leitura


  process.stdin.resume();
  process.stdin.setEncoding('utf8');

  process.stdin.on('data', chunk => {
    console.log('chunk: ', chunk)
  });

  process.stdin.on('end', () => {
    console.log('--- END ---')
  });

Streams de Escrita


  const myStream = getWritableStreamSomehow();

  myStream.write('some data');
  myStream.write('some more data');

  myStream.on('error', err => console.log('eita', err));

  myStream.end('done writing data');

Pipes


  const read = fs.createReadStream('file.txt');
  const gzip = zlib.createGzip();
  const write = fs.createWriteStream('file.txt.gz');
  
  read.pipe(gzip).pipe(write);

  process.stdin.on('data',
    chunk => process.stdout.write(chunk)
  );

  process.stdin.pipe(process.stdout);

HTTP Streams


  app.get('/get-image', (req, res) => {
    fs.readFile('/large/image/path', (error, data) => {
      res.end(data);
    });
  });

  app.get('/get-image', (req, res) => {
    fs.readFile('/large/image/path', (error, data) => {
      res.end(data);
    });
  });

  app.get('/stream', (req, res) => {
    const stream = fs.createReadStream('/large/image/path');
    stream.pipe(res);
  });

Reactive Extensions


  > npm install rx-node

  const RxNode = require('rx-node');

  RxNode.fromReadableStream(process.stdin)
    .merge(anotherStream)
    .map(data => (foo: 'bar', data))
    .subscribe(data => console.log(data));

Clusters


  const http = require('http');
  const cluster = require('cluster');
  const numCPUs = require('os').cpus().length;

  const http = require('http');
  const cluster = require('cluster');
  const numCPUs = require('os').cpus().length;

  if (cluster.isMaster) {
    for (var i = 0; i < numCPUs; i++)
      cluster.fork();
  } else {

  const http = require('http');
  const cluster = require('cluster');
  const numCPUs = require('os').cpus().length;

  if (cluster.isMaster) {
    for (var i = 0; i < numCPUs; i++)
      cluster.fork();
  } else {
    http.createServer((req, res) => {
      res.writeHead(200);
      res.end(`hello world! ${process.pid}`);
    }).listen(8000);
  }

Load Balancing

Child Process

  • Fork
  • Spawn
  • Exec

process.fork


  const fs = require('fs');
  const process = require('child_process');
  const p = process.fork('program.js');
  
  p.stdout.on('data', data => {
    console.log('stdout: ' + data);
  });

process.spawn


  const fs = require('fs');
  const process = require('child_process');
  const p = process.spawn('ls', ['-lh', '/usr']);
  
  p.stdout.on('data', data => {
    console.log('stdout: ' + data);
  });

process.exec


  const fs = require('fs');
  const process = require('child_process');
  
  process.exec('cat *.js bad_file', (error, stdout, stderr) => {
    if (error) {
      console.error(`exec error: ${error}`);
      return;
    }
    console.log(`stdout: ${stdout}`);
    console.log(`stderr: ${stderr}`);
  });

Referências

Perguntas?

Obrigado! =)

@willgmbr

github.com/willgm