Giới thiệu ngắn về Nodejs và ứng dụng realtime.
Trang 2I N T R O TO N O D E J S
L E V E L O N E
Trang 3-INTRO TO NODE.JS
WHAT IS NODE.JS?
It’s fast because it’s mostly C code
Allows you to build scalable network
applications using JavaScript on the server-side.
V8 JavaScript Runtime
Node.js
Trang 4Like a chat server
Trang 6Read file from Filesystem
whenever you’re complete, print the contents
Do Something else
Trang 7INTRO TO NODE.JS
BLOCKING VS NON-BLOCKING
var contents = fs.readFileSync('/etc/hosts');
console.log(contents);
console.log('Doing something else');
• Blocking Code
• Non-Blocking Code
console.log('Doing something else');Stop process until complete
fs.readFile('/etc/hosts', function(err, contents) {
});
Trang 8fs.readFile('/etc/hosts', function(err, contents) {
console.log(contents);
});
INTRO TO NODE.JS
CALLBACK ALTERNATE SYNTAX
var callback = function(err, contents) {
console.log(contents);
}
fs.readFile('/etc/hosts', callback);
Same as
Trang 9fs.readFile('/etc/hosts', callback);
fs.readFile('/etc/inetcfg', callback);
var callback = function(err, contents) {
console.log(contents);
}
Trang 10NODE.JS HELLO DOG
$ curl http://localhost:8080
Hello, this is dog
How we require modules
Status code in header
Response body Close the connection
Listen for connections on this port
$ node hello.js Run the server
Trang 11THE EVENT LOOP
var http = require('http');
http.createServer(function(request, response) {
}).listen(8080);
console.log('Listening on port 8080 ');
Starts the Event Loop when finished
Run the Callback
Trang 12INTRO TO NODE.JS
WHY JAVASCRIPT?
“JavaScript has certain characteristics that make it very different than other dynamic languages, namely that it has
no concept of threads Its model of concurrency is
completely based around events.” - Ryan Dahl
Trang 13THE EVENT LOOP
Known Events
request
Checking
for Events
Trang 14INTRO TO NODE.JS
WITH LONG RUNNING PROCESS
Represent long running process
Trang 16TWO CALLBACKS TIMELINE
Request comes in, triggers request event
Request Callback executes
Trang 17WITH BLOCKING TIMELINE
Request comes in, triggers request event
Request Callback executes
setTimeout executed Request comes in, waits for server
Request comes in
triggers setTimeout event setTimeout Callback executed Wasted Time
Request Callback executes
Trang 18INTRO TO NODE.JS
• Calls out to web services
TYPICAL BLOCKING THINGS
• Reads/Writes on the Database
• Calls to extensions
Trang 19E V E N TS
L E V E L T W O
Trang 20When ‘click’ event is triggered
attach
$("p").on("click", function(){ });
Trang 22E V E N T S
CUSTOM EVENT EMITTERS
var logger = new EventEmitter();
logger.emit('error', 'Spilled Milk');
ERR: Spilled Milk
logger.emit('error', 'Eggs Cracked');
var EventEmitter = require('events').EventEmitter;
listen for error event
logger.on('error', function(message){
console.log('ERR: ' + message);
});
ERR: Eggs Cracked
events
Trang 23When ‘request’ event is emitted
function(request, response){ }
emit
attach
Trang 24E V E N T S
HTTP ECHO SERVER
http.createServer(function(request, response){ });
But what is really going on here?
http://nodejs.org/api/
Trang 25E V E N T S
BREAKING IT DOWN
http.createServer(function(request, response){ });
Trang 26http.createServer(function(request, response){ });
E V E N T S
ALTERNATE SYNTAX
var server = http.createServer();
function(request, response){ });server.on('request',
This is how we add
Trang 27ST R E A M S
L E V E L T H R E E
Trang 28-S T R E A M -S
WHAT ARE STREAMS?
Start Processing Immediately
Streams can be readable, writeable, or both
Trang 29response.write("Dog is running.");
readable stream writable stream
Trang 30Lets print what we receive from the request.
http.createServer(function(request, response) {
request.on('data', function(chunk) {
console.log(chunk.toString());
Trang 31S T R E A M S
LETS CREATE AN ECHO SERVER
http.createServer(function(request, response) {
request.on('data', function(chunk) {
Trang 32S T R E A M S
LETS CREATE AN ECHO SERVER!
http.createServer(function(request, response) {
cat 'bleh.txt' | grep 'something'
Kinda like on the command line
Trang 33S T R E A M S
READING AND WRITING A FILE
var fs = require('fs');
var file = fs.createReadStream("readme.md");
var newFile = fs.createWriteStream("readme_copy.md");
require filesystem module
file.pipe(newFile);
Trang 35THE AWESOME STREAMING
Trang 36Writable stream slower
than readable stream
Using pipe solves this problem
Trang 37THINK OF A MILK JUG
Trang 38PIPE SOLVES BACKPRESSURE
readStream.resume();
});
Pause when writeStream is full
writeStream.on('drain', function(){
readStream.on('data', function(chunk) {
writeStream.write(chunk);
});
var buffer_good =
if (!buffer_good) readStream.pause(); returns false
if kernel buffer full
Resume when ready to write again
readStream.pipe(writeStream);
All encapsulated in
Trang 39S T R E A M S
FILE UPLOADING PROGRESS
Trang 40S T R E A M S
FILE UPLOADING PROGRESS
$ curl upload-file file.jpg http://localhost:8080
Trang 41S T R E A M S
DOCUMENTATION http://nodejs.org/api/
Stability Scores
Trang 43S T R E A M S
REMEMBER THIS CODE?
var newFile = fs.createWriteStream("readme_copy.md");
http.createServer(function(request, response) {
request.pipe(newFile);
}).listen(8080);
request.on('data', function(chunk) {
uploadedBytes += chunk.length;
var progress = (uploadedBytes / fileBytes) * 100;
response.write("progress: " + parseInt(progress, 10) + "%\n");});
var uploadedBytes = 0;
var fileBytes = request.headers['content-length'];
Trang 44S T R E A M S
SHOWING PROGRESS
Trang 45M O D U L ES
L E V E L F O U R
Trang 47exports defines what require returns
var hello = function() {
console.log("hello!");
Trang 48M O D U L E S
EXPORT MULTIPLE FUNCTIONS
my_module.js
app.js
var foo = function() { }
var bar = function() { }
bar
var baz = function() { }
baz
“private”
Trang 49var request = http.request(options, function(response){
response.on('data', function(data){
console.log(data);
Trang 51var makeRequest = require('./make_request');
makeRequest("Here's looking at you, kid");
makeRequest("Hello, this is dog");
Where does require look for modules?
Trang 52var make_request = require('./make_request')
var make_request = require(' /make_request')
var make_request = require('/Users/eric/nodes/make_request')
Trang 53M O D U L E S
NPM: THE USERLAND SEA
Package manager for node
• Comes with node
Trang 54M O D U L E S
INSTALLING A NPM MODULE
$ npm install request https://github.com/mikeal/request
In /Home/my_app
Home my_app node_modules request
Installs into local node_modules directory
var request = require('request');
In /Home/my_app/app.js
Loads from local node_modules directory
Trang 57my_app node_modules connect
Installs into the node_modules directory
Trang 58connect node_modules formidable
Trang 59"connect": "~1.8.7" >=1.8.7 <1.9.0 Considered safe
"connect": "~1.8" >=1.8 <2.0.0 API could change
"connect"Ranges : "~1" >=1.0.0 <2.0.0 Dangerous
Trang 60E X P R ES S
L E V E L F I V E
Trang 61-E X P R -E S S
EXPRESS
“Sinatra inspired web development framework for Node.js insanely fast, flexible, and simple”
• Easy route URLs to callbacks
• Middleware (from Connect)
• Environment based configuration
• Redirection helpers
• File Uploads
Trang 62E X P R E S S
INTRODUCING EXPRESS
$ npm install express
var express = require('express');
var app = express.createServer();
app.get('/', function(request, response) {
Trang 63E X P R E S S
EXPRESS ROUTES
app.js
route definition get the last 10 tweets for screen_name
pipe the request to response
var request = require('request');
var url = require('url');
app.get('/tweets/:username', function(req, response) {
var username = req.params.username;
Trang 64E X P R E S S
EXPRESS ROUTES
Trang 65E X P R E S S
EXPRESS + HTML
Trang 66request(url, function (err, res, body) {
var tweets = JSON parse (body);
response.render( 'tweets.ejs' , {tweets: tweets, name: username}); });
});
<h1> Tweets for @<%= name %> </h1>
<ul>
<% tweets.forEach( function (tweet){ %>
<li><%= tweet.text %></li>
<% }); %>
</ul>
Trang 67E X P R E S S
EXPRESS TEMPLATES
Trang 68<% tweets.forEach( function (tweet){ %>
<li><%= tweet.text %></li>
<% }); %>
</ul>
tweets.ejs
layout.ejs
Trang 69E X P R E S S
EXPRESS TEMPLATES
Trang 70S O C K E T I O
L E V E L S I X
Trang 71-S O C K E T I O
CHATTR
Trang 72S O C K E T I O
WEBSOCKETS
Traditional request/response cycle
Trang 73Using duplexed websocket connection
S O C K E T I O
WEBSOCKETS
Trang 74S O C K E T I O
SOCKET.IO FOR WEBSOCKETS
var socket = require('socket.io');
var app = express.createServer();
var io = socket.listen(app);
Abstracts websockets with fallbacks
io.sockets.on('connection', function(client) {
});
console.log('Client connected ');
<script src= "/socket.io/socket.io.js" ></script>
var server = io.connect('http://localhost:8080');
Trang 75S O C K E T I O
SENDING MESSAGES TO CLIENT
io.sockets.on('connection', function(client) {
});
console.log('Client connected ');
<script src= "/socket.io/socket.io.js" ></script>
var server = io.connect('http://localhost:8080');
<script>
</script>
app.js
index.html
client.emit('messages', { hello: 'world' });
server.on('messages', function (data) {
});
alert(data.hello);
emit the ‘messages’ event on the client
listen for ‘messages’ events
Trang 76S O C K E T I O
CHATTR HELLO WORLD
Trang 77S O C K E T I O
SENDING MESSAGES TO SERVER
io.sockets.on('connection', function(client) {
console.log(data);
$('#chat_form').submit(function(e){
var message = $('#chat_input').val();
socket.emit('messages', message);
});
listen for ‘messages’ events
emit the ‘messages’ event on the server
Trang 78S O C K E T I O
CHATTR HELLO WORLD
Trang 80broadcast message to all other clients connected
client.broadcast.emit("messages", data);
server.on('messages', function(data) { insertMessage(data) });
insert message into the chat
Trang 81S O C K E T I O
BROADCASTING MESSAGES
Trang 82S O C K E T I O
SAVING DATA ON THE SOCKET
io.sockets.on('connection', function(client) {
client.on('join', function(name) {
client.set('nickname', name);
with this client
server.on('connect', function(data) {
$('#status').html('Connected to chattr');
nickname = prompt("What is your nickname?");
server.emit('join', nickname);
users nickname
Trang 83S O C K E T I O
SAVING DATA ON THE CLIENT
io.sockets.on('connection', function(client) {
});
app.js
client.on('join', function(name) {
client.set('nickname', name);
with this client
client.on('messages', function(data){
});
client.broadcast.emit("chat", name + ": " + message);
client.get('nickname', function(err, name) {
});
get the nickname of this client before broadcasting message
broadcast with the name and message
Trang 84S O C K E T I O
SAVING DATA ON THE CLIENT
Trang 85P E R S I ST I N G DATA
L E V E L S E V E N
Trang 86-P E R S I S T I N G D A T A
RECENT MESSAGES
Trang 87io.sockets.on('connection', function(client) {
client.on('join', function(name) {
client.set('nickname', name);
client.broadcast.emit("chat", name + " joined the chat");});
client.on("messages", function(message){
client.get("nickname", function(error, name) {
client.broadcast.emit("messages", name + ": " + message);
app.js
Trang 88io.sockets.on('connection', function(client) {
client.on("messages", function(message){
client.get("nickname", function(error, name) {
app.js
storeMessage(name, message);
var messages = []; store messages in array
var storeMessage = function(name, data){
messages.push({name: name, data: data});
if (messages.length > 10) {
messages.shift();
}
}
add message to end of array
if more than 10 messages long,
remove the last one when client sends a message
call storeMessage
Trang 89messages.forEach(function(message) {
client.emit("messages", message.name + ": " + message.data); }); iterate through messages array
and emit a message on the connecting
client for each one
Trang 90
P E R S I S T I N G D A T A
RECENT MESSAGES
Trang 92P E R S I S T I N G D A T A
REDIS DATA STRUCTURES
Strings SET, GET, APPEND, DECR, INCR
Hashes HSET, HGET, HDEL, HGETALL
Lists LPUSH, LREM, LTRIM, RPOP, LINSERT
Sets SADD, SREM, SMOVE, SMEMBERS
Sorted Sets ZADD, ZREM, ZSCORE, ZRANK
Trang 93P E R S I S T I N G D A T A
REDIS COMMAND DOCUMENTATION
Trang 94P E R S I S T I N G D A T A
NODE REDIS
Trang 95client.get("message1", function(err, reply){
console.log(reply);
});
P E R S I S T I N G D A T A
REDIS
"hello, yes this is dog"
var redis = require('redis');
var client = redis.createClient();
client.set("message1", "hello, yes this is dog");
client.set("message2", "hello, no this is spider");
commands are non-blocking
$ npm install redis
Trang 96P E R S I S T I N G D A T A
REDIS LISTS: PUSHING
Add a string to the “messages” list
client.lpush("messages", message, function(err, reply){ console.log(reply);
var message = "Hello, no this is spider";
client.lpush("messages", message, function(err, reply){ console.log(reply);
replies with list length
Add another string to “messages”
var message = "Hello, this is dog";
Trang 97P E R S I S T I N G D A T A
REDIS LISTS: RETRIEVING
Using LPUSH & LTRIM
trim keeps first two strings and removes the rest
Retrieving from list
client.lrange("messages", 0, -1, function(err, messages){ console.log(messages);
})
[ "Hello, no this is spider" , "Oh sorry, wrong number" ]
replies with all strings in list
var message = "Oh sorry, wrong number";
client.lpush("messages", message, function(err, reply){
client.ltrim("messages", 0, 1);
});
Trang 98P E R S I S T I N G D A T A
CONVERTING MESSAGES TO REDIS
var storeMessage = function(name, data){
messages.push({name: name, data: data});
Trang 99P E R S I S T I N G D A T A
CONVERTING STOREMESSAGE
var storeMessage = function(name, data){
}
var redisClient = redis.createClient();
var message = JSON.stringify({name: name, data: data});
redisClient.lpush("messages", message, function(err, response) {redisClient.ltrim("messages", 0, 10);
Trang 100P E R S I S T I N G D A T A
OUTPUT FROM LIST
client.on('join', function(name) {
});
messages.forEach(function(message) {
client.emit("messages", message.name + ": " + message.data);});
app.js
Trang 101P E R S I S T I N G D A T A
OUTPUT FROM LIST
client.on('join', function(name) {
});
messages.forEach(function(message) {
client.emit("messages", message.name + ": " + message.data);});
redisClient.lrange("messages", 0, -1, function(err, messages){messages = messages.reverse();
message = JSON.parse(message);
});
app.js
reverse so they are emitted in correct order parse into JSON object
Trang 102P E R S I S T I N G D A T A
IN ACTION
Trang 103P E R S I S T I N G D A T A
CURRENT CHATTER LIST
Sets are lists of unique data
client.sadd("names", "Dog");
client.sadd("names", "Spider");
client.sadd("names", "Gregg");
client.srem("names", "Spider");
client.smembers( "names" , function (err, names){ console log (names);
});
[ "Dog" , "Gregg" ]
reply with all members of set add & remove members of the names set
Trang 104P E R S I S T I N G D A T A
AĐING CHATTERS
client.on('join', function(name){
client.broadcast.emit("ađ chatter", name);
redisClient.sađ("chatters", name);
});
app.js
notify other clients a chatter has joined
ađ name to chatters set
index.html
server.on('ađ chatter', insertChatter);
var insertChatter = function(name) {
var chatter = $('<li>'+name+'</li>').datắnamé, name); $('#chatters').append(chatter);
}