These are the notes I took during the Node.js basic course from www.codeschool.com. It was a very good course. It guides through the basics of how to start with NodeJS.
Table of contents
- Lesson 1
- Lesson 2: Events
- Lesson 3: Streams
- Lesson 4: Modules
- Lesson 5: Express
- Lesson 6: Sockets
- Lesson 7: Persisting Data
Lesson 1
- Node.js is not a framework. There are Web frameworks based on Node.js but Node.js itself is not. It is on much lower level than frameworks.
- Main thing with Node.js is that it's event based; the event loop; non blocking by design
- It's the V8 JavaScript Runtime from Chrome wrapped in extra stuff, and written in C
- There is no concurrency, it's like single threaded server
- JavaScript was chosen because it also has no concurrency and this fits more
Minimal server
var http = require(‘http’);
http.createServer(function(request, response) {
response.writeHead(200);
response.write(“Hello, this is Bla”);
response.end()
}).listen(8080);
- it's registering the request event
- it tells what should happen on that event
Serving index.html
http.createServer(function(request, response) {
response.writeHead(200);
fs.readFile('index.html', function(error, contents){
response.write(contents);
response.end();
});
}).listen(8080);
Lesson 2: Events
- in Node.js objects can emit events
- every such object is an instance of EventEmitter
- the http.createServer is in fact taking the callback for 'request' event, we could as well write server.on('request', callback)
- multiple handlers can be registered for same event
Custom EventEmitter
var events = require('events');
var EventEmitter = events.EventEmitter;
var chat = new EventEmitter();
chat.on('message', function(message){
console.log(message);
});
chat.emit('message', 'blabla');
Lesson 3: Streams
- they are good for transmitting huge amount of data, so that we can do it chunk by chunk
- we cover the streams2 api
- streams are e.g. the request (readable stream) and response (writable stream) input parameters in the createServer callback function; they are both open inside the function
- readable stream is also an EventEmitter!
Echoing the request to the user
response.writeHead(200);
request.pipe(response); // echo the request to the user
File upload
var file = fs.createWriteStream(‘file1.txt’);
request.pipe(file);
request.on(‘end’, function(){
response.end(‘uploaded!’)
});
File upload with progress
var file = fs.createWriteStream('file1.txt');
var fileBytes = request.headers[content-length];
var uploadedBytes = 0;
request.on('readable', function(){
var chunk = null;
while(null !== (chunk = file.read())){
uploadedBytes += chunk.length;
var progress = (uploadedBytes/fileBytes)*100;
response.write("Progress:"+ parseInt(progress,10)+"%\n");
}
});
request.pipe(file);
request.on('end', function(){
response.end('uploaded!')
});
var fileBytes = request.headers[content-length];
var uploadedBytes = 0;
request.on('readable', function(){
var chunk = null;
while(null !== (chunk = file.read())){
uploadedBytes += chunk.length;
var progress = (uploadedBytes/fileBytes)*100;
response.write("Progress:"+ parseInt(progress,10)+"%\n");
}
});
request.pipe(file);
request.on('end', function(){
response.end('uploaded!')
});
Other useful things
- file.pipe(process.stdout); - like console.log
- reading in chunks:
file.on('readable', function(){
var chunk;
while(null !== (chunk = file.read())){
console.log(chunk.toString());
}
}); - don't close writer stream once pipe is done:
file.pipe(destFile, {end:false});
Lesson 4: Modules
my_module.js:
var foo = function(){...};
var bar = function(){...};
var baz = function(){...};
exports.foo = foo;
exports.bar = bar;
app.js:
var m = require("./my_module");
m.foo();
m.bar();
var foo = function(){...};
var bar = function(){...};
var baz = function(){...};
exports.foo = foo;
exports.bar = bar;
app.js:
var m = require("./my_module");
m.foo();
m.bar();
- you can also do module.exports = foo, and then call directly foo(), but in this way you can export only one function
- if you don't provide the "./" prefix for the module name, it will look in node_modules directory of the app, then the same directory in your home directory, if not then in /home, and if not then at the root path.
- npm - Package Manager for Node - module repository, dependency management, easily publish your own modules, see npmjs.org
- package.json - good practice to have this file in root of your app, with app info and required dependency versions; then, when you run "npm install", these dependencies will be installed if not there yet;
- package.json is also present in module root folder, as one module may depend on another one
- semantic versioning: x.x.x, you can also specify ~1.8 to get the latest 1.8.x version; see www.semver.org
Lesson 5: Express
- is a web framework for node
Basic example
require('express');
var app = express();
app.get('/', function(request, response){
response.sendFile(__dirname + "/index.html");
});
app.listen(8080);
Request with dynamic URI param
app.get('/tweets/:username', function(request, response){
var username = request.params.username;
options = {
protocol: "http:",
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);
});
app.listen(8080);
Templates - Embedded Java Script
- npm install --save ejs
- the templates are in "views" directory of your app by default
- to put the data in the template, use a callback function in request function:
request(twitterUrl).pipe(response);
request(twitterUrl, function(err,res,body){
var tweets = JSON.parse(body);
//that's the data that will end up in the template:
response.locals = {tweets:tweets, name:username};
response.render('tweets.ejs');
});
tweets.ejs:
<h1>Tweets for <%= name %></h1>
<ul>
<% tweets.forEach(function(tweet){
<li><%= tweet.text %></li>
<%});%>
</ul>
Lesson 6: Sockets
- npm install --save socket.io
- var io = require("socket.io")(server) - the server which was created with "createServer(app)", where app is express server.. in this way socket.io and express share same http server
- we write a chatroom app
Server side
app.js
var express = require('express');
var app = express();
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io')(server);
io.on('connection', function(client){
console.log("New client connected..");
//when client sends a message, emit it to all other clients
client.on('messages', function(data){
client.broadcast.emit('question',data);
});
//or just emit one dummy message to the client
client.emit('messages',{foo:"bar"});
});
server.listen(8080);
Client side
index.html:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost:8080');
//the client can receive messages like this
server.on('messages', function(data){
console.log(data.foo);
});
</script>
Lesson 7: Persisting Data
- still the chatroom example: if someone joins later, they don't see the previous messages; so we store them in server in memory - but if server restarts, then it's bad
- so we can use a DB - Node.js has drivers for most DBses which are NON Blocking!
- example: Redis (key value store), very good docu: npm install --save redis:
I'm skipping that part, it's redis specific
Comments
Want to leave a comment? Visit this post's issue page
on GitHub and just post your comment as the issue's comment (you'll need a GitHub account. What? Like you don't have one yet?!).
Comments: