Node.js : Streams – Une métaphore – Un pattern



Node.js : Streams – Une métaphore – Un pattern

0 0


nodejsparis-streams

Slides du talks sur les Streams à NodejsParis le 12 Mars 2014

On Github Floby / nodejsparis-streams

Node.js : Streams

Hello world, notes

Qui suis-je ?

Florent Jaby

  • Consultant pour OCTO Technology
  • Noder depuis 2009
  • @Floby sur Github et le reste d'internet

Qu'est-ce qu'un stream ?

  • Une métaphore
  • Un pattern
  • Une classe

Une métaphore

Un flux de données directionnel et ordonné
node.js - v0.8 node.js - v0.10 Streams 1 Streams 2 push-stream pull-stream

Un pattern

Omniprésent dans la philosophie UNIX

  • FILE* en C sous linux
  • cat "file.txt" | gzip | tee "file.txt.gz"
  • Les sockets TCP

http://blog.izs.me/post/48281998870/unix-philosophy-and-node-js

Appartient au super-pattern de Message-Passing

"message passing sends a message to a process and relies on the process to select and invoke the actual code to run" "The justifications for using an intermediate layer essentially falls into two categories: encapsulation and distribution"

http://en.wikipedia.org/wiki/Message_passing

Une classe

... 4 en réalité

Readable

var Readable = require('stream').Readable;
// ...

readable.on('readable', function () {
  var chunk = readable.read();
});
readable.on('end', onEnd);


readable.on('data', function (data) {
  // don't really use this please...
});

Writable

var Writable = require('stream').Writable;
// ...

writable.write(chunk);
writable.end();

var written = writable.write(chunk);
// written is true or false

Duplex

var Duplex = require('stream').Duplex;
// ...

var socket = net.createConnection(80, 'google.com');

socket.write("GET /\r\n\r\n");
socket.on('readable', function () {
  console.log(socket.read());
})

Transform

var Transform = require('stream').Transform;
// ...

var gzip = zlib.createGzip();

process.stdin
  .pipe(gzip)
  .pipe(process.stdout);

pipe ?

Avec un flux en écriture et en lecture, on peut chaîner les redirections de flux

http.createServer(function (req, res) {
  var busboy = new Busboy({ headers: req.headers });
  var pack = tar.pack();
  var gzip = zlib.createGzip();

  busboy
    .on('file', function (field, stream, filename) {
      var entry = tar.entry({name: filename});
      filename.pipe(entry);
    })
    .on('finish', function () {
      pack.finalize();
    });

  req.pipe(busboy);
  pack.pipe(gzip).pipe(res);
}).listen(80);
          

En tant qu'utilisateur de la classe Stream :

  • Utilisez la méthode pipe()
  • Si vous utilisez les autres, vous devriez écrire votre propre stream

objectMode

Les streams peuvent en réalité aussi transporter des objets serialisés en JSON

Des usages cools

Logging structuré : Bunyan

  • Logging d'objets plutôt que de lignes
  • Indépendant du transport
  • Peut passer par plusieurs étapes de traitement
  • Peut être stocké sur n'importe quel support

WebSockets : Shoe

  • Interface Stream pour les websockets sur le client et le serveur
  • Fallback sur du polling pour les navigateurs incompatibles
  • J'ai testé, ça marche !

RPC : DNode

  • RPC agnostique au transport
  • Support des callbacks de manière transparente
  • Fonctionne même dans le navigateur !

Introduction du pattern  A.pipe(B).pipe(A)

Replication multi-master : Scuttlebutt

  • Une implémentation simple du protocole Gossip
  • Agnostique au transport
  • extensible à plusieurs types de données
  • fonctionne aussi dans le navigateur !

Utilisation du pattern  A.pipe(B).pipe(A)

Manipulation de BDD : LevelDB

  • Read/Write par streams
  • Map/Reduce par streams
  • Filter par streams

Gourous

  • Dominic Tarr (@dominictarr)
  • James Halliday (@substack)
  • Jake Verbaten (@raynos)

Merci !

Florent Jaby @Floby