0% found this document useful (0 votes)
14 views107 pages

Code School Real Time Web With Nodejs

Node.js is a server-side JavaScript runtime built on Chrome's V8 engine, enabling the creation of scalable network applications. It supports both blocking and non-blocking code execution, with a focus on event-driven programming and streams for efficient data handling. The document also covers modules, event emitters, and the use of npm for package management.

Uploaded by

Hạnh Teedy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views107 pages

Code School Real Time Web With Nodejs

Node.js is a server-side JavaScript runtime built on Chrome's V8 engine, enabling the creation of scalable network applications. It supports both blocking and non-blocking code execution, with a focus on event-driven programming and streams for efficient data handling. The document also covers modules, event emitters, and the use of npm for package management.

Uploaded by

Hạnh Teedy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 107

INTRO TO NODE .

JS
- LEV EL O NE -
WHAT IS NODE.JS?
Allows you to build scalable network
applications using JavaScript on the server-side.
Node.js
V8 JavaScript Runtime

It’s fast bec a use it ’ s mo stly C c o de

INTRO TO NODE.JS
WHAT COULD YOU BUILD?
• Websocket Server Like a c hat server
• Fast File Upload Client
• Ad Server
• Any Real-Time Data Apps

INTRO TO NODE.JS
WHAT IS NODE.JS NOT?
• A Web Framework
• For Beginners It’s very low level
• Multi-threaded
s in g le t h rea de d ser ver
You can think of it as a

INTRO TO NODE.JS
OBJECTIVE: PRINT FILE CONTENTS
• Blocking Code
Read file from Filesystem, set equal to “contents”
Print contents
Do something else

• Non-Blocking Code
Read file from Filesystem
whenever you’re complete, print the contents
Do Something else

This is a “Callback”
INTRO TO NODE.JS
BLOCKING VS NON-BLOCKING
• Blocking Code
var contents = fs.readFileSync('/etc/hosts');
unt il c o mp lete
console.log(contents); Stop proc es s
console.log('Doing something else');

• Non-Blocking Code
fs.readFile('/etc/hosts', function(err, contents) {
console.log(contents);
});
console.log('Doing something else');

INTRO TO NODE.JS
CALLBACK ALTERNATE SYNTAX
fs.readFile('/etc/hosts', function(err, contents) {
console.log(contents);
});

Same as
var callback = function(err, contents) {
console.log(contents);
}

fs.readFile('/etc/hosts', callback);

INTRO TO NODE.JS
BLOCKING VS NON-BLOCKING
var callback = function(err, contents) {
console.log(contents);
}

fs.readFile('/etc/hosts', callback);
fs.readFile('/etc/inetcfg', callback);

blocking

0s 5s 10s
non-blocking

0s 5s 10s
INTRO TO NODE.JS
NODE.JS HELLO DOG
hello.js
var http = require('http'); How we require modules
http.createServer(function(request, response) {
response.writeHead(200); Status code in header
response.write("Hello, this is dog."); Response body
response.end(); Close the connection
}).listen(8080); Listen for connections on this port

console.log('Listening on port 8080...');

$ node hello.js Run the server $ curl http://localhost:8080

Listening on port 8080... Hello, this is dog.


THE 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


Known Events
request
Checking
for
Events
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

INTRO TO NODE.JS
THE EVENT LOOP
Event Queue Known Events
Checking request
close for connection
request Events close

Events processed one at a time


WITH LONG RUNNING PROCESS
var http = require('http');

http.createServer(function(request, response) {
response.writeHead(200);
response.write("Dog is running.");
setTimeout(function(){ Represent long running process
response.write("Dog is done.");
response.end();
}, 5000); 5000ms = 5 seconds
}).listen(8080);

INTRO TO NODE.JS
TWO CALLBACKS HERE
var http = require('http');

http.createServer(function(request, response) { request


response.writeHead(200);
response.write("Dog is running.");
setTimeout(function(){ timeout
response.write("Dog is done.");
response.end();
}, 5000);
}).listen(8080);

INTRO TO NODE.JS
TWO CALLBACKS TIMELINE
Request comes in, triggers request event
Request Callback executes
setTimeout registered
Request comes in, triggers request event
Request Callback executes
setTimeout registered
triggers setTimeout event
request setTimeout Callback executes
triggers setTimeout event
timeout
setTimeout Callback

0s 5s 10s
WITH BLOCKING TIMELINE
Request comes in, triggers request event
Request Callback executes
setTimeout executed
Request comes in, waits for server
triggers setTimeout event
setTimeout Callback executed
Wasted Time
Request comes in
Request Callback executes

0s 5s 10s
TYPICAL BLOCKING THINGS
• Calls out to web services
• Reads/Writes on the Database
• Calls to extensions

INTRO TO NODE.JS
-
EVENTS
LE VE L TWO -
EVENTS IN THE DOM
The DOM triggers Events
you can listen for those events
The DOM click
submit events
attach hover

$("p").on("click",
! function(){ ... });

When ‘click’ event is triggered

EVENTS
EVENTS IN NODE
Many objects in Node emit events
net.Server
request
EventEmitter
event
fs.readStream
data
EventEmitter
event

EVENTS
CUSTOM EVENT EMITTERS
var EventEmitter = require('events').EventEmitter;

events
var logger = new EventEmitter(); error warn info
logger.on('error', function(message){
console.log('ERR: ' + message);
});
listen for error event
logger.emit('error', 'Spilled Milk');

ERR: Spilled Milk

logger.emit('error', 'Eggs Cracked');

ERR: Eggs Cracked

EVENTS
EVENTS IN NODE
Many objects in Node emit events
net.Server emit request
EventEmitter
event
attach
function(request,
! response){ .. }

When ‘request’ event is emitted

EVENTS
HTTP ECHO SERVER
http.createServer(function(request,
! response){ ... });

But what is really going on here?


http://nodejs.org/api/

EVENTS
BREAKING IT DOWN
http.createServer(function(request,
! response){ ... });

EVENTS
ALTERNATE SYNTAX
http.createServer(function(request,
! response){ ... });

Same as
var server = http.createServer();
!
server.on('request', function(request, response){ ... });

This is how we add


add event listeners
server.on('close', function(){ ... });

EVENTS
STREAM S
- L EVEL TH REE -
WHAT ARE STREAMS?

Start Processing
Immediately
Streams can be readable, writeable, or both

STREAMS
STREAMING RESPONSE
readable stream writable stream
http.createServer(function(request, response) {
response.writeHead(200);
response.write("Dog is running.");
setTimeout(function(){
response.write("Dog is done.");
response.end();
}, 5000);
}).listen(8080);

Our clients receive "Dog is running."


(5 seconds later)
"Dog is done."

STREAMS
HOW TO READ FROM THE REQUEST?
events
Readable Stream emit data
EventEmitter end
Lets print what we receive from the request.
http.createServer(function(request, response) {
response.writeHead(200);
request.on('data', function(chunk) {
console.log(chunk.toString());
});

request.on('end', function() {
response.end();
});
}).listen(8080)

STREAMS
LETS CREATE AN ECHO SERVER
http.createServer(function(request, response) {
response.writeHead(200);
request.on('data', function(chunk) {
response.write(chunk); request.pipe(response);
});

request.on('end', function() {
response.end();
});
}).listen(8080)

STREAMS
LETS CREATE AN ECHO SERVER!
http.createServer(function(request, response) {
response.writeHead(200);
request.pipe(response);
}).listen(8080)

$ curl -d 'hello' http://localhost:8080

Hello on client
Kinda like on the command line
cat 'bleh.txt' | grep 'something'

STREAMS
READING AND WRITING A FILE
var fs = require('fs'); require filesystem module
var file = fs.createReadStream("readme.md");
var newFile = fs.createWriteStream("readme_copy.md");

file.pipe(newFile);

STREAMS
UPLOAD A FILE
var fs = require('fs');
var http = require('http');

http.createServer(function(request, response) {
var newFile = fs.createWriteStream("readme_copy.md");
request.pipe(newFile);

request.on('end', function() {
response.end('uploaded!');
});
}).listen(8080);

$ curl --upload-file readme.md http://localhost:8080

uploaded!

STREAMS
THE AWESOME STREAMING
server

client storage
original file
transferred file
non-blocking
0s 5s 10s
BACK PRESSURE!
server
Writable stream slower
than readable stream
client storage
original file
transferred file

Using pipe solves this problem


THINK OF A MILK JUG
milkStream.pause();

Once milk jug is drained


milkStream.resume();
});
PIPE SOLVES BACKPRESSURE
Pause when writeStream is full
readStream.on('data', function(chunk) {
var buffer_good = writeStream.write(chunk);
if (!buffer_good) readStream.pause(); returns false
});
if kernel buffer full
Resume when ready to write again
writeStream.on('drain', function(){
readStream.resume();
});

All encapsulated in
readStream.pipe(writeStream);
FILE UPLOADING PROGRESS

STREAMS
FILE UPLOADING PROGRESS
$ curl --upload-file file.jpg http://localhost:8080

Outputs:
progress: 3%
progress: 6% • HTTP Server
progress: 9% We’re going to need:
progress: 12% • File System
progress: 13%
...
progress: 99%
progress: 100%

STREAMS
DOCUMENTATION http://nodejs.org/api/
Stability Scores

STREAMS
REMEMBER THIS CODE?
var fs = require('fs');
var http = require('http');

http.createServer(function(request, response) {
var newFile = fs.createWriteStream("readme_copy.md");
request.pipe(newFile);

request.on('end', function() {
response.end('uploaded!');
});
}).listen(8080);

STREAMS
REMEMBER THIS CODE?
http.createServer(function(request, response) {
var newFile = fs.createWriteStream("readme_copy.md");
var fileBytes = request.headers['content-length'];
var uploadedBytes = 0;

request.pipe(newFile);

request.on('data', function(chunk) {
uploadedBytes += chunk.length;
var progress = (uploadedBytes / fileBytes) * 100;
response.write("progress: " + parseInt(progress, 10) + "%\n");
});
...
}).listen(8080);

STREAMS
SHOWING PROGRESS

STREAMS
MOD UL ES
- LEV EL F OUR -
REQUIRING MODULES
var http = require('http'); http.js
var fs = require('fs'); fs.js
How does ‘require’ return the libraries?
How does it find these files?

MODULES
LETS CREATE OUR OWN MODULE
custom_hello.js custom_goodbye.js
var hello = function() { exports.goodbye = function() {
console.log("hello!"); console.log("bye!");
} }
exports = hello;

app.js exports defines what require returns


var hello = require('./custom_hello');
var gb = require('./custom_goodbye');
hello();
gb.goodbye();

require('./custom_goodbye').goodbye(); If we only need to call once


MODULES
EXPORT MULTIPLE FUNCTIONS
my_module.js
var foo = function() { ... }
var bar = function() { ... } my_module.js
var baz = function() { ... }
foo baz
exports.foo = foo
exports.bar = bar bar
app.js
var myMod = require('./my_module');
myMod.foo(); “private”
myMod.bar();

MODULES
MAKING HTTP REQUESTS
var http = require('http'); app.js
var message = "Here's looking at you, kid.";
var options = {
host: 'localhost', port: 8080, path: '/', method: 'POST'
}

var request = http.request(options, function(response){


response.on('data', function(data){
console.log(data); logs response body
});
});
request.write(message); begins request
request.end(); finishes request

MODULES
ENCAPSULATING THE FUNCTION
var http = require('http'); app.js
var makeRequest = function(message) {
var options = {
host: 'localhost', port: 8080, path: '/', method: 'POST'
}

var request = http.request(options, function(response){


response.on('data', function(data){
console.log(data);
});
});
request.write(message);
request.end();
}

makeRequest("Here's looking at you, kid.");

MODULES
CREATING & USING A MODULE
var http = require('http'); make_request.js
var makeRequest = function(message) {
...
}

exports = makeRequest;

var makeRequest = require('./make_request'); app.js


makeRequest("Here's looking at you, kid");
makeRequest("Hello, this is dog");

Where does require look for modules?

MODULES
REQUIRE SEARCH
var make_request = require('./make_request') look in same directory
var make_request = require('../make_request') look in parent directory
var make_request = require('/Users/eric/nodes/make_request')

/Home/eric/my_app/app.js Search in node_modules directories


var make_request = require('make_request')

• /Home/eric/my_app/node_modules/
• /Home/eric/node_modules/make_request.js
• /Home/node_modules/make_request.js
• /node_modules/make_request.js
MODULES
NPM: THE USERLAND SEA
Package manager for node
• Comes with node
• Module Repository
• Dependency Management
• Easily publish modules
• “Local Only”
“Core” is small. “Userland” is large.

MODULES
INSTALLING A NPM MODULE
In /Home/my_app
$ npm install request https://github.com/mikeal/request

Installs into local node_modules directory


Home my_app node_modules reques

In /Home/my_app/app.js
var request = require('request');

Loads from local node_modules directory

MODULES
LOCAL VS GLOBAL
Install modules with executables globally
$ npm install coffee-script -g global
$ coffee app.coffee

Global npm modules can’t be required


var coffee = require('coffee-script');

$ npm install coffee-script Install them locally


var coffee = require('coffee-script');

MODULES
FINDING MODULES
npm registry
npm command line

$ npm search request

toolbox.no.de
github search

MODULES
DEFINING YOUR DEPENDENCIES
my_app/package.json
{ version number
"name": "My App",
"version": "1",
"dependencies": {
"connect": "1.8.7"
}
}

$ npm install

Installs into the node_modules directory


my_app node_modules connect

MODULES
DEPENDENCIES
my_app/package.json
"dependencies": {
"connect": "1.8.7" No conflicting modules!
}

Installs sub-dependencies
my_app node_modules connect

connect node_modules qs

connect node_modules mime

connect node_modules formidable

MODULES
SEMANTIC VERSIONING
Major Minor Patch
"connect": "1.8.7" 1 . 8 . 7

Ranges
"connect": "~1" >=1.0.0 <2.0.0 Dangerous
"connect": "~1.8" >=1.8 <2.0.0 API could change
"connect": "~1.8.7" >=1.8.7 <1.9.0 Considered safe
http://semver.org/

MODULES
EXPRESS
- L EVEL FIVE -
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

EXPRESS
INTRODUCING EXPRESS
$ npm install express
var express = require('express');

var app = express.createServer();

root route
app.get('/', function(request, response) {
response.sendfile(__dirname + "/index.html");
}); current directory
app.listen(8080);

$ curl http://localhost:8080/
> 200 OK

EXPRESS
EXPRESS ROUTES
var request = require('request'); app.js
var url = require('url');
route definition
app.get('/tweets/:username', function(req, response) {

var username = req.params.username;

options = {
protocol: "http:", get the last 10 tweets for screen_name
host: 'api.twitter.com',
pathname: '/1/statuses/user_timeline.json',
query: { screen_name: username, count: 10}
}

var twitterUrl = url.format(options);


request(twitterUrl).pipe(response);
});
pipe the request to response
EXPRESS
EXPRESS ROUTES

EXPRESS
EXPRESS + HTML

EXPRESS
EXPRESS TEMPLATES
app.get('/tweets/:username', function(req, response) { app.js
...
request(url, function(err, res, body) {
var tweets = JSON.parse(body);
response.render('tweets.ejs', {tweets: tweets, name: username});
});
});

<h1>Tweets for @<%= name %></h1> tweets.ejs


<ul>
<% tweets.forEach(function(tweet){ %>
<li><%= tweet.text %></li>
<% }); %>
</ul>

EXPRESS
EXPRESS TEMPLATES

EXPRESS
TEMPLATE LAYOUTS
<h1>Tweets for @<%= name %></h1> tweets.ejs
<ul>
<% tweets.forEach(function(tweet){ %>
<li><%= tweet.text %></li>
<% }); %>
</ul>

<!DOCTYPE html> layout.ejs


<html>
<head>
<title>Tweets</title>
</head>
<body>
<%- body %>
</body>
</html>

EXPRESS
EXPRESS TEMPLATES

EXPRESS
SOCKET.IO
- L EVEL S IX -
CHATTR

S O C K E T. I O
WEBSOCKETS

browser traditional server


Traditional request/response cycle

S O C K E T. I O
WEBSOCKETS

browser socket.io
Using duplexed websocket connection

S O C K E T. I O
SOCKET.IO FOR WEBSOCKETS
Abstracts websockets with fallbacks
$ npm install socket.io

var socket = require('socket.io'); app.js


var app = express.createServer();
var io = socket.listen(app);

io.sockets.on('connection', function(client) {
console.log('Client connected...');
});

<script src="/socket.io/socket.io.js"></script> index.html


<script>
var server = io.connect('http://localhost:8080');
</script>

S O C K E T. I O
SENDING MESSAGES TO CLIENT
io.sockets.on('connection', function(client) { app.js
console.log('Client connected...');

emit the ‘messages’ event on the client


client.emit('messages', { hello: 'world' });
});

<script src="/socket.io/socket.io.js"></script> index.html


<script>
var server = io.connect('http://localhost:8080');
server.on('messages', function (data) {
alert(data.hello);
}); listen for ‘messages’ events
</script>

S O C K E T. I O
CHATTR HELLO WORLD

S O C K E T. I O
SENDING MESSAGES TO SERVER
io.sockets.on('connection', function(client) { app.js
client.on('messages', function (data) {
console.log(data);
}); listen for ‘messages’ events
});

<script>
var server = io.connect('http://localhost:8080');
index.html
$('#chat_form').submit(function(e){
var message = $('#chat_input').val();
emit the ‘messages’ event on the server
socket.emit('messages', message);
});
</script>

S O C K E T. I O
CHATTR HELLO WORLD

S O C K E T. I O
BROADCASTING MESSAGES
app.js
!
clients socket.broadcast.emit("message", 'Hello');

server

S O C K E T. I O
BROADCASTING MESSAGES
io.sockets.on('connection', function(client) { app.js
client.on('messages', function (data) {
client.broadcast.emit("messages", data);
});
broadcast message to all other clients connected
});

<script>
index.html
...
server.on('messages', function(data) { insertMessage(data) });
</script> insert message into the chat

S O C K E T. I O
BROADCASTING MESSAGES

S O C K E T. I O
SAVING DATA ON THE SOCKET
io.sockets.on('connection', function(client) { app.js
client.on('join', function(name) {
client.set('nickname', name); set the nickname associated
});
});
with this client
<script>
var server = io.connect('http://localhost:8080');
index.html
server.on('connect', function(data) {
$('#status').html('Connected to chattr');
nickname = prompt("What is your nickname?");

server.emit('join', nickname); notify the server of the


}); users nickname
</script>

S 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); set the nickname associated
});
with this client
client.on('messages', function(data){
get the nickname of this client before broadcasting message
client.get('nickname', function(err, name) {
client.broadcast.emit("chat", name + ": " + message);
}); broadcast with the name and message
});
});

S O C K E T. I O
SAVING DATA ON THE CLIENT

S O C K E T. I O
PERSIST ING DATA
- LEV EL S EVEN -
RECENT MESSAGES

PERSISTING DATA
RECENT MESSAGES
io.sockets.on('connection', function(client) { app.js
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);
});
});
});

PERSISTING DATA
STORING MESSAGES
var messages = []; store messages in array app.js
var storeMessage = function(name, data){
messages.push({name: name, data: data}); add message to end of array
if (messages.length > 10) {
messages.shift(); if more than 10 messages long,
}
}
remove the last one
io.sockets.on('connection', function(client) {
client.on("messages", function(message){
client.get("nickname", function(error, name) {
storeMessage(name, message);
}); when client sends a message
});
});
call storeMessage

PERSISTING DATA
EMITTING MESSAGES
io.sockets.on('connection', function(client) { app.js
...
client.on('join', function(name) {
messages.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

PERSISTING DATA
RECENT MESSAGES

PERSISTING DATA
PERSISTING STORES
• MongoDB All non-blocking!
• CouchDB
• PostgreSQL
• Memcached
• Riak

Redis is a key-value store


PERSISTING DATA
REDIS DATA STRUCTURES
data structure commands
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...

PERSISTING DATA
REDIS COMMAND DOCUMENTATION

PERSISTING DATA
NODE REDIS

PERSISTING DATA
REDIS
$ npm install redis

var redis = require('redis');


var client = redis.createClient();

client.set("message1", "hello, yes this is dog");


client.set("message2", "hello, no this is spider");

key value
client.get("message1", function(err, reply){
console.log(reply); "hello, yes this is dog"
});

commands are non-blocking


PERSISTING DATA
REDIS LISTS: PUSHING
Add a string to the “messages” list
var message = "Hello, this is dog";
client.lpush("messages", message, function(err, reply){
console.log(reply);
}); "1” replies with list length
Add another string to “messages”
var message = "Hello, no this is spider";
client.lpush("messages", message, function(err, reply){
console.log(reply);
}); "2”

PERSISTING DATA
REDIS LISTS: RETRIEVING
Using LPUSH & LTRIM
var message = "Oh sorry, wrong number";
client.lpush("messages", message, function(err, reply){
client.ltrim("messages", 0, 1);
trim keeps first two strings
});
and removes the rest
Retrieving from list
client.lrange("messages", 0, -1, function(err, messages){

})
console.log(messages);
replies with all strings in list

["Hello, no this is spider", "Oh sorry, wrong number"]

PERSISTING DATA
CONVERTING MESSAGES TO REDIS
var storeMessage = function(name, data){ app.js
messages.push({name: name, data: data});

if (messages.length > 10) {


messages.shift();
}
}

Let’s use the List data-structure

PERSISTING DATA
CONVERTING STOREMESSAGE
var redisClient = redis.createClient(); app.js
var storeMessage = function(name, data){
var message = JSON.stringify({name: name, data: data});
need to turn object into string to store in redis
redisClient.lpush("messages", message, function(err, response) {
redisClient.ltrim("messages", 0, 10);
});

}
keeps newest 10 items

PERSISTING DATA
OUTPUT FROM LIST
client.on('join', function(name) { app.js
messages.forEach(function(message) {
client.emit("messages", message.name + ": " + message.data);
});
});

PERSISTING DATA
OUTPUT FROM LIST
app.js
client.on('join', function(name) {
redisClient.lrange("messages", 0, -1, function(err, messages){
messages = messages.reverse(); reverse so they are emitted
in correct order
messages.forEach(function(message) {
message = JSON.parse(message); parse into JSON object
client.emit("messages", message.name + ": " + message.data);
});
});
});

PERSISTING DATA
IN ACTION

PERSISTING DATA
CURRENT CHATTER LIST
Sets are lists of unique data
add & remove members of the names set
client.sadd("names", "Dog");
client.sadd("names", "Spider");
client.sadd("names", "Gregg");

client.srem("names", "Spider");

reply with all members of set


!
client.smembers("names", function(err, names){
console.log(names);
});

["Dog", "Gregg"]

PERSISTING DATA
ADDING CHATTERS
client.on('join', function(name){ app.js
notify other clients a chatter has joined
client.broadcast.emit("add chatter", name);
redisClient.sadd("chatters", name);
}); add name to chatters set
server.on('add chatter', insertChatter); index.html
var insertChatter = function(name) {
var chatter = $('<li>'+name+'</li>').data('name', name);
$('#chatters').append(chatter);
}

PERSISTING DATA
ADDING CHATTERS (CONT)
client.on('join', function(name){ app.js
notify other clients a chatter has joined
client.broadcast.emit("add chatter", name);

redisClient.smembers('names', function(err, names) {


names.forEach(function(name){
client.emit('add chatter', name);
});
});
emit all the currently logged in chatters
to the newly connected client

redisClient.sadd("chatters", name);
}); add name to chatters set

PERSISTING DATA
REMOVING CHATTERS
remove chatter when they disconnect from server
client.on('disconnect', function(name){ app.js
client.get('nickname', function(err, name){
client.broadcast.emit("remove chatter", name);

redisClient.srem("chatters", name);
});
});

server.on('remove chatter', removeChatter); index.html


var removeChatter = function(name) {
$('#chatters li[data-name=' + name + ']').remove();
}

PERSISTING DATA
WELCOME TO CHATTR

PERSISTING DATA

You might also like