nodev8HTTP/1.1single-thread event loopEn tous cas c'est plus facile qu'Erlang, et vachement plus puissant que PHP
git clone --depth 1 git://github.com/joyent/node.git # or git clone git://github.com/joyent/node.git if you want # to checkout a stable tag cd node git checkout v0.4.12 # optional. Note: master is unstable ./configure make -j2 # -j sets the number of jobs to run [sudo] make install
Les navigateurs supportent tous partiellement HTTP/1.1. Idem pour les serveurs.
UPGRADEETag, If-Modified-SinceNode.JS supporte tout le protocole.
Don't Repeat Yourself
Don't Reinvent the Wheel
var fs = require('fs');
fs.readFile('fichier1', function (err, content) {
if (err) {
// Cas d'erreur
} else {
// "content" instance de "Buffer"
console.log(content.toString());
}
}
console.log("afficher avant réponse I/O");
var fs = require('fs');
fs.readFile('fichier1', /* ... */ );
fs.readFile('fichier2', /* ... */ );
fs.readFile('fichier3', /* ... */ );
console.log("lecture de 3 fichiers");
console.log("impossible de prédire")
console.log("l'ordre de réponse");
Le roi ordonne à ses messagers, qui reviennent dès qu'ils le peuvent, et le roi traite les réponses au fur et à mesure, une à la fois.
On y reviendra plus tard...
Pour l'instant, place au fun!
var app = require('http').createServer(function (req, res) {
/* ... */
}).listen(8000);
var sockets = require('socket.io').listen(app).sockets;
// Nouveau client
sockets.on('connection', function (client) {
// Évènement envoyé par le client
client.on('client→serveur', function (data) {
// Envoyer un évènement à tous les autres clients
client.broadcast.emit('serveur → client', 'data');
});
});
La librairie client est intégrée dans le serveur
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
L'API est uniforme et cohérente
// Connexion
var socket = io.connect();
// Évènement envoyé par le serveur
socket.on('serveur → client', function (data) {
/* ... */
});
// Envoyer un évènement au serveur
$('#button').bind('click', function () {
socket.emit('client → serveur', 'data');
});
Ce serait cool si je pouvais envoyer des données du serveur direct aux clients
// Serveur
client.on('next', function () {
sockets.emit('next');
});
// Client
socket.on('next', function () {
$.deck('next');
});
Vous auriez pu suivre cette présentation en live, mais ce n'est plus vraiment "live" là :)
Par contre tout est sur github: github.com/naholyr/lyonjs2011-10
|
La télécommande http://server:1338/remote-control (Pwd: coucougamin)
|
![]() |
|
Les slides http://server:1338 |
Les slides défilent en temps réel sur votre écran |
Mais Node.JS est mono-tâche
fs.readFile('fichier1', function (err, content) {
calcul_tres_long(); // 10 s
});
fs.readFile('fichier2', function (err, content) {
// j'ai fini de lire "fichier2" ...
// ... mais je dois attendre ...
// ... la fin de "calcul_tres_long()"
// :(
});
Noob friendly ?
Certains "experts" (*) voient ça d'un mauvais œil.
Node.JS is cancer
(NDLT: dans ce contexte, "expert" = "gros élitiste de mes deux")
fork, spawn, un queue externe...)fork, cluster)
var cluster = require('cluster');
cluster(require('./app'))
.use(cluster.logger('logs'))
.use(cluster.stats())
.listen(3000);
node cluster "./app.js"
Detected 2 cpus Worker 6790 online Worker 6789 online
Les sockets de Socket.IO :/
Qui...
var redis = require("redis");
var client = redis.createClient();
// S'inscrire à un channel
client.subscribe("channel");
client.on('subscribe', function (channel) {});
// Recevoir un message sur ce channel
client.on('message', function (channel, msg) {});
// Envoyer un message sur ce channel
client.publish("channel", "my message");
/etc/redis/redis.conf
var RedisStore = require('connect-redis')(connect);
connect.session({
"secret": 'my secret string',
"store": new RedisStore(/* info */)
})
var RedisStore = socketio.RedisStore;
io.configure(function () {
io.set('store', new RedisStore({
// client déjà instancié
"redisClient": client,
/* info */
})
);
});
Bonne pratique: utilisez toujours un reverse-proxy, même avec une seule machine derrière :)
Ah oups. Par contre c'est en dév actif. La solution: comme on ne pourra pas faire de scaling horizontal sur ce "bus de message", avoir une instance de Redis dédié à cette tâche et uniquement cette tâche pour limiter sa charge.
Pas d'API native pour ça, néanmoins si le besoin se fait sentir le plus simple est sans doute de faire du séquentiel (tout en gardant les API asynchrones non bloquantes, grâce à des modules comme async). Sinon en jouant avec un callback unique et un flag global on doit pouvoir faire quelque chose.
Son troll était vraiment velu, malpoli, mal amené, plein de dénigrement puant, bref horripilant. Néanmoins il a apporté de vrais débats, et a pointé du doigt un aspect très important et hélas négligé de Node par les débutants: son côté mono-thread. Néanmoins j'insiste sur le fait que ce n'est pas un défaut du langage mais un choix de conception (qui a l'avantage de terriblement simplifier la gestion des "race conditions" par exemple). Sans son troll, la question du clustering et du fork de process ne se serait pas posée aussi fort, et c'est donc positif.
En gros à chaque fois qu'on doit faire beaucoup de réseau ou de filesystem, il est meilleur que les langages "classiques" de part son API asynchrone (pendant que j'attends le résultat d'une requête SQL, je ne glande pas, je continue à répondre aux autres utilisateurs par exemple). De plus malgré une API haut niveau, on a accès à toutes les couches basses. Quelques use-case ont été cités: streaming, site web à forte concurrence d'accès, pseudo temps réel, et même une appli qui avait servi à contrôler du débit en sortie de routeurs (très bel exemple).