SlideShare uma empresa Scribd logo
1 de 76
Node.js Patterns
For the Discerning Developer
C. Aaron Cois, Ph.D. :: Carnegie Mellon University, SEI
Me
@aaroncois
www.codehenge.net
github.com/cacois
Disclaimer: Though I am an employee of the Software Engineering Institute at Carnegie Mellon University, this work was
not funded by the SEI and does not reflect the work or opinions of the SEI or its customers.
Let’s talk about
Node.js Basics
• JavaScript
• Asynchronous
• Non-blocking I/O
• Event-driven
So, JavaScript?
The Basics
Prototype-based Programming
• JavaScript has no classes
• Instead, functions define objects
function Person() {}
var p = new Person();
Image: http://tech2.in.com/features/gaming/five-wacky-gaming-hardware-to-look-forward-to/315742
Prototype
Classless Programming
What do classes do for us?
• Define local scope / namespace
• Allow private attributes / methods
• Encapsulate code
• Organize applications in an object-oriented
way
Prototype-based Programming
function Person(firstname, lastname){
this.firstname = firstname;
this.lastname = lastname;
}
var p = new Person(“Philip”, “Fry”);
What else can do that?
Prototype Inheritance
function Person(firstname, lastname){
this.firstname = firstname;
this.lastname = lastname;
}
// Create new class
Employee = Person;//Inherit from superclass
Employee.prototype = {
marital_status: 'single',
salute: function() {
return 'My name is ' + this.firstname;
}
}
var p = new Employee (“Philip”, “Fry”);
Watch out!
function Person(firstname, lastname){
this.firstname = firstname;
this.lastname = lastname;
}
// Create new class
Employee = Person;//Inherit from superclass
Employee.prototype = {
marital_status: 'single',
salute: function() {
return 'My name is ' + this.firstname;
}
}
var p = new Employee (“Philip”, “Fry”);
The ‘new’ is very important!
If you forget, your new object will
have global scope internally
Another option
function Person(firstname, lastname){
this.firstname = firstname;
this.lastname = lastname;
}
Employee = Person;//Inherit from superclass
Employee.prototype = {
marital_status: 'single',
salute: function() {
return 'My name is ' + this.firstname;
}
}
var p = Object.create(Employee);
p.firstname = 'Philip';
p.lastname = 'Fry';
Works, but you can’t initialize
attributes in constructor
Anti-Pattern: JavaScript Imports
• Spread code around files
• Link libraries
• No way to maintain private local
scope/state/namespace
• Leads to:
– Name collisions
– Unnecessary access
Pattern: Modules
• An elegant way of encapsulating and
reusing code
• Adapted from YUI, a few years before
Node.js
• Takes advantage of the anonymous
closure features of JavaScript
Image: http://wallpapersus.com/
Modules in the Wild
var http = require('http'),
io = require('socket.io'),
_ = require('underscore');
If you’ve programmed in Node, this looks
familiar
Anatomy of a module
var privateVal = 'I am Private!';
module.exports = {
answer: 42,
add: function(x, y) {
return x + y;
}
}
mymodule.js
Usage
mod = require('./mymodule');
console.log('The answer: '+ mod.answer);
var sum = mod.add(4,5);
console.log('Sum: ' + sum);
Modules are used everywhere
// User model
var mongoose = require('mongoose')
, Schema = mongoose.Schema;
var userSchema = new Schema({
name: {type: String, required: true},
email: {type: String, required: true},
githubid: String,
twitterid: String,
dateCreated: {type: Date, default: Date.now}
});
userSchema.methods.validPassword = function validPass(pass) {
// validate password…
}
module.exports = mongoose.model('User', userSchema);
My config files? Modules.
var config = require('config.js');
console.log('Configured user is: ' + config.user);
module.exports = {
user: 'maurice.moss'
}
config.js
app.js
Asynchronous
Asynchronous Programming
• Node is entirely asynchronous
• You have to think a bit differently
• Failure to understand the event loop and
I/O model can lead to anti-patterns
Event Loop
Node.js
Event Loop
Node app
Event Loop
Node.js
Event Loop
Node apps pass async
tasks to the event loop,
along with a callback
(function, callback)
Node app
Event Loop
Node.js
Event Loop
The event loop efficiently
manages a thread pool and
executes tasks efficiently…
Thread
1
Thread
2
Thread
n
…
Task 1
Task 2
Task 3
Task 4
Return 1
Callback1()
…and executes each callback as
tasks complete
Node app
Async I/O
The following tasks should be done
asynchronously, using the event loop:
• I/O operations
• Heavy computation
• Anything requiring blocking
Your Node app is single-threaded
Anti-pattern: Synchronous Code
for (var i = 0; i < 100000; i++){
// Do anything
}
Your app only has one thread, so:
…will bring your app to a grinding halt
Anti-pattern: Synchronous Code
But why would you do that?
Good question.
But in other languages (Python), you may do this:
for file in files:
f = open(file, ‘r’)
print f.readline()
Anti-pattern: Synchronous Code
The Node.js equivalent is:
Based on examples from: https://github.com/nodebits/distilled-patterns/
var fs = require('fs');
for (var i = 0; i < files.length; i++){
data = fs.readFileSync(files[i]);
console.log(data);
}
…and it will cause severe performance
problems
Pattern: Async I/O
fs = require('fs');
fs.readFile('f1.txt','utf8',function(err,data){
if (err) {
// handle error
}
console.log(data);
});
Async I/O
fs = require('fs');
fs.readFile('f1.txt','utf8',function(err,data){
if (err) {
// handle error
}
console.log(data);
});
Anonymous, inline callback
Async I/O
fs = require('fs');
fs.readFile('f1.txt','utf8',
function(err,data){
if (err) {
// handle error
}
console.log(data);
}
);
Equivalent
syntax
Callback Hell
When working with callbacks, nesting can
get quite out of hand…
Callback Hell
var db = require('somedatabaseprovider');
//get recent posts
http.get('/recentposts', function(req, res) {
// open database connection
db.openConnection('host', creds,function(err, conn){
res.param['posts'].forEach(post) {
conn.query('select * from users where
id='+post['user'],function(err,users){
conn.close();
res.send(users[0]);
});
}
});
});
Callback Hell
var db = require('somedatabaseprovider');
//get recent posts
http.get('/recentposts', function(req, res) {
// open database connection
db.openConnection('host', creds,function(err, conn){
res.param['posts'].forEach(post) {
conn.query('select * from users where
id='+post['user'],function(err,users){
conn.close();
res.send(users[0]);
});
}
});
});
Get recent posts from web
service API
Callback Hell
var db = require('somedatabaseprovider');
//get recent posts
http.get('/recentposts', function(req, res) {
// open database connection
db.openConnection('host', creds,function(err, conn){
res.param['posts'].forEach(post) {
conn.query('select * from users where
id='+post['user'],function(err,users){
conn.close();
res.send(users[0]);
});
}
});
});
Open connection to DB
Callback Hell
var db = require('somedatabaseprovider');
//get recent posts
http.get('/recentposts', function(req, res) {
// open database connection
db.openConnection('host', creds,function(err, conn){
res.param['posts'].forEach(post) {
conn.query('select * from users where
id='+post['user'],function(err,users){
conn.close();
res.send(users[0]);
});
}
});
});
Get user from DB for each
post
Callback Hell
var db = require('somedatabaseprovider');
//get recent posts
http.get('/recentposts', function(req, res) {
// open database connection
db.openConnection('host', creds,function(err, conn){
res.param['posts'].forEach(post) {
conn.query('select * from users where
id='+post['user'],function(err,users){
conn.close();
res.send(users[0]);
});
}
});
});
Return users
Callback Hell
var db = require('somedatabaseprovider');
//get recent posts
http.get('/recentposts', function(req, res) {
// open database connection
db.openConnection('host', creds,function(err, conn){
res.param['posts'].forEach(post) {
conn.query('select * from users where
id='+post['user'],function(err,users){
conn.close();
res.send(users[0]);
});
}
});
});
Anti-Pattern: Callback Hell
fs.readdir(source, function(err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function(filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function(err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function(width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(destination+'w’+width+'_’+filename, function(err){
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})
http://callbackhell.com/
Solutions
• Separate anonymous callback functions
(cosmetic)
• Async.js
• Promises
• Generators
Pattern:
Separate Callbacks
fs = require('fs');
callback = function(err,data){
if (err) {
// handle error
}
console.log(data);
}
fs.readFile('f1.txt','utf8',callback);
Can Turn This
var db = require('somedatabaseprovider');
http.get('/recentposts', function(req, res){
db.openConnection('host', creds, function(err,
conn){
res.param['posts'].forEach(post) {
conn.query('select * from users where id=' +
post['user'],function(err,results){
conn.close();
res.send(results[0]);
});
}
});
});
Into This
var db = require('somedatabaseprovider');
http.get('/recentposts', afterRecentPosts);
function afterRecentPosts(req, res) {
db.openConnection('host', creds, function(err, conn) {
afterDBConnected(res, conn);
});
}
function afterDBConnected(err, conn) {
res.param['posts'].forEach(post) {
conn.query('select * from users where id='+post['user'],afterQuery);
}
}
function afterQuery(err, results) {
conn.close();
res.send(results[0]);
}
This is really a Control Flow issue
Pattern: Async.js
Async.js provides common patterns for
async code control flow
https://github.com/caolan/async
Also provides some common functional
programming paradigms
Serial/Parallel Functions
• Sometimes you have linear serial/parallel
computations to run, without branching
callback growth
Function
1
Function
2
Function
3
Function
4
Function
1
Function
2
Function
3
Function
4
Serial/Parallel Functions
async.parallel([
function(){ ... },
function(){ ... }
], callback);
async.series([
function(){ ... },
function(){ ... }
]);
Serial/Parallel Functions
async.parallel([
function(){ ... },
function(){ ... }
], callback);
async.series([
function(){ ... },
function(){ ... }
], callback);
Single Callback
Waterfall
Async.waterfall([
function(callback){ ... },
function(input,callback){ ... },
function(input,callback){ ... },
], callback);
Map
var arr = ['file1','file2','file3'];
async.map(arr, fs.stat, function(err, results){
// results is an array of stats for each file
console.log('File stats: ' +
JSON.stringify(results));
});
Filter
var arr = ['file1','file2','file3'];
async.filter(arr, fs.exists, function(results){
// results is a list of the existing files
console.log('Existing files: ' + results);
});
With great power…
Carefree
var fs = require('fs');
for (var i = 0; i < 10000; i++) {
fs.readFileSync(filename);
}
With synchronous code, you can loop as much
as you want:
The file is opened once each iteration.
This works, but is slow and defeats the point of
Node.
Synchronous Doesn’t Scale
What if we want to scale to 10,000+
concurrent users?
File I/O becomes
the bottleneck
Users get in a
long line
Async to the Rescue
var fs = require('fs');
function onRead(err, file) {
if (err) throw err;
}
for (var i = 0; i < 10000; i++) {
fs.readFile(filename, onRead);
}
What happens if I do this asyncronously?
Ruh Roh
The event loop is fast
This will open the file 10,000 times at once
This is unnecessary…and on most systems,
you will run out of file descriptors!
Pattern:
The Request Batch
• One solution is to batch requests
• Piggyback on existing requests for the
same file
• Each file then only has one open request
at a time, regardless of requesting clients
// Batching wrapper for fs.readFile()
var requestBatches = {};
function batchedReadFile(filename, callback) {
// Is there already a batch for this file?
if (filename in requestBatches) {
// if so, push callback into batch
requestBatches[filename].push(callback);
return;
}
// If not, start a new request
var callbacks = requestBatches[filename] = [callback];
fs.readFile(filename, onRead);
// Flush out the batch on complete
function onRead(err, file) {
delete requestBatches[filename];
for(var i = 0;i < callbacks.length; i++) {
// execute callback, passing arguments along
callbacks[i](err, file);
}
}
}
Based on examples from: https://github.com/nodebits/distilled-patterns/
// Batching wrapper for fs.readFile()
var requestBatches = {};
function batchedReadFile(filename, callback) {
// Is there already a batch for this file?
if (filename in requestBatches) {
// if so, push callback into batch
requestBatches[filename].push(callback);
return;
}
// If not, start a new request
var callbacks = requestBatches[filename] = [callback];
fs.readFile(filename, onRead);
// Flush out the batch on complete
function onRead(err, file) {
delete requestBatches[filename];
for(var i = 0;i < callbacks.length; i++) {
// execute callback, passing arguments along
callbacks[i](err, file);
}
}
}
Based on examples from: https://github.com/nodebits/distilled-patterns/
Is this file already being read?
// Batching wrapper for fs.readFile()
var requestBatches = {};
function batchedReadFile(filename, callback) {
// Is there already a batch for this file?
if (filename in requestBatches) {
// if so, push callback into batch
requestBatches[filename].push(callback);
return;
}
// If not, start a new request
var callbacks = requestBatches[filename] = [callback];
fs.readFile(filename, onRead);
// Flush out the batch on complete
function onRead(err, file) {
delete requestBatches[filename];
for(var i = 0;i < callbacks.length; i++) {
// execute callback, passing arguments along
callbacks[i](err, file);
}
}
}
Based on examples from: https://github.com/nodebits/distilled-patterns/
If not, start a new file read
operation
// Batching wrapper for fs.readFile()
var requestBatches = {};
function batchedReadFile(filename, callback) {
// Is there already a batch for this file?
if (filename in requestBatches) {
// if so, push callback into batch
requestBatches[filename].push(callback);
return;
}
// If not, start a new request
var callbacks = requestBatches[filename] = [callback];
fs.readFile(filename, onRead);
// Flush out the batch on complete
function onRead(err, file) {
delete requestBatches[filename];
for(var i = 0;i < callbacks.length; i++) {
// execute callback, passing arguments along
callbacks[i](err, file);
}
}
}
Based on examples from: https://github.com/nodebits/distilled-patterns/
When read finished, return to
all requests
Usage
//Request the resource 10,000 times at once
for (var i = 0; i < 10000; i++) {
batchedReadFile(file, onComplete);
}
function onComplete(err, file) {
if (err) throw err;
else console.log('File contents: ' + file);
}
Based on examples from: https://github.com/nodebits/distilled-patterns/
Pattern:
The Request Batch
This pattern is effective on many read-type
operations, not just file reads
Example: also good for web service API
calls
Shortcomings
Batching requests is great for high request
spikes
Often, you are more likely to see steady
requests for the same resource
This begs for a caching solution
Pattern:
Request Cache
Let’s try a simple cache
Persist the result forever and check for new
requests for same resource
// Caching wrapper around fs.readFile()
var requestCache = {};
function cachingReadFile(filename, callback) {
//Do we have resource in cache?
if (filename in requestCache) {
var value = requestCache[filename];
// Async behavior: delay result till next tick
process.nextTick(function () { callback(null, value); });
return;
}
// If not, start a new request
fs.readFile(filename, onRead);
// Cache the result if there is no error
function onRead(err, contents) {
if (!err) requestCache[filename] = contents;
callback(err, contents);
}
}
Based on examples from: https://github.com/nodebits/distilled-patterns/
Usage
// Request the file 10,000 times in series
// Note: for serial requests we need to iterate
// with callbacks, rather than within a loop
var its = 10000;
cachingReadFile(file, next);
function next(err, contents) {
console.log('File contents: ' + contents);
if (!(its--)) return;
cachingReadFile(file, next);
}
Based on examples from: https://github.com/nodebits/distilled-patterns/
Almost There!
You’ll notice two issues with the Request
Cache as presented:
• Concurrent requests are an issue again
• Cache invalidation not handled
Let’s combine cache and batch strategies:
// Wrapper for both caching and batching of requests
var requestBatches = {}, requestCache = {};
function readFile(filename, callback) {
if (filename in requestCache) { // Do we have resource in cache?
var value = requestCache[filename];
// Delay result till next tick to act async
process.nextTick(function () { callback(null, value); });
return;
}
if (filename in requestBatches) {// Else, does file have a batch?
requestBatches[filename].push(callback);
return;
}
// If neither, create new batch and request
var callbacks = requestBatches[filename] = [callback];
fs.readFile(filename, onRead);
// Cache the result and flush batch
function onRead(err, file) {
if (!err) requestCache[filename] = file;
delete requestBatches[filename];
for (var i=0;i<callbacks.length;i++) { callbacks[i](err, file); }
}
}
Based on examples from: https://github.com/nodebits/distilled-patterns/
scale-fs
I wrote a module for scalable File I/O
https://www.npmjs.org/package/scale-fs
Usage:
var fs = require(’scale-fs');
for (var i = 0; i < 10000; i++) {
fs.readFile(filename);
}
Final Thoughts
Most anti-patterns in Node.js come from:
• Sketchy JavaScript heritage
• Inexperience with Asynchronous Thinking
Remember, let the Event Loop do the heavy
lifting!
Thanks
Code samples from this talk at:
https://github.com/cacois/node-
patterns-discerning
Disclaimer
Though I am an employee of the Software
Engineering Institute at Carnegie Mellon
University, this wok was not funded by the
SEI and does not reflect the work or
opinions of the SEI or its customers.
Let’s chat
@aaroncois
www.codehenge.net
github.com/cacois
Node.js
Event Loop
The event loop efficiently
manages a thread pool and
executes tasks efficiently…
Thread
1
Thread
2
Thread
n
…
Task 1
Task 2
Task 3
Task 4
Return 1
Callback1()
…and executes each callback as
tasks complete
Node.js
app
Node apps pass async
tasks to the event loop,
along with a callback
(function, callback)
1 2
3

Mais conteúdo relacionado

Mais procurados

A million connections and beyond - Node.js at scale
A million connections and beyond - Node.js at scaleA million connections and beyond - Node.js at scale
A million connections and beyond - Node.js at scaleTom Croucher
 
Introduction to Node js
Introduction to Node jsIntroduction to Node js
Introduction to Node jsAkshay Mathur
 
Java script at backend nodejs
Java script at backend   nodejsJava script at backend   nodejs
Java script at backend nodejsAmit Thakkar
 
Node.js and How JavaScript is Changing Server Programming
Node.js and How JavaScript is Changing Server Programming  Node.js and How JavaScript is Changing Server Programming
Node.js and How JavaScript is Changing Server Programming Tom Croucher
 
Node js presentation
Node js presentationNode js presentation
Node js presentationmartincabrera
 
Introduction to Node.js
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.jsVikash Singh
 
RESTful API In Node Js using Express
RESTful API In Node Js using Express RESTful API In Node Js using Express
RESTful API In Node Js using Express Jeetendra singh
 
Node.js, for architects - OpenSlava 2013
Node.js, for architects - OpenSlava 2013Node.js, for architects - OpenSlava 2013
Node.js, for architects - OpenSlava 2013Oscar Renalias
 
NodeJS - Server Side JS
NodeJS - Server Side JS NodeJS - Server Side JS
NodeJS - Server Side JS Ganesh Kondal
 
node.js: Javascript's in your backend
node.js: Javascript's in your backendnode.js: Javascript's in your backend
node.js: Javascript's in your backendDavid Padbury
 
Node Architecture and Getting Started with Express
Node Architecture and Getting Started with ExpressNode Architecture and Getting Started with Express
Node Architecture and Getting Started with Expressjguerrero999
 
Complete MVC on NodeJS
Complete MVC on NodeJSComplete MVC on NodeJS
Complete MVC on NodeJSHüseyin BABAL
 
All aboard the NodeJS Express
All aboard the NodeJS ExpressAll aboard the NodeJS Express
All aboard the NodeJS ExpressDavid Boyer
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
Use Node.js to create a REST API
Use Node.js to create a REST APIUse Node.js to create a REST API
Use Node.js to create a REST APIFabien Vauchelles
 
Non-blocking I/O, Event loops and node.js
Non-blocking I/O, Event loops and node.jsNon-blocking I/O, Event loops and node.js
Non-blocking I/O, Event loops and node.jsMarcus Frödin
 
Comet with node.js and V8
Comet with node.js and V8Comet with node.js and V8
Comet with node.js and V8amix3k
 

Mais procurados (20)

A million connections and beyond - Node.js at scale
A million connections and beyond - Node.js at scaleA million connections and beyond - Node.js at scale
A million connections and beyond - Node.js at scale
 
node.js dao
node.js daonode.js dao
node.js dao
 
Introduction to Node js
Introduction to Node jsIntroduction to Node js
Introduction to Node js
 
Java script at backend nodejs
Java script at backend   nodejsJava script at backend   nodejs
Java script at backend nodejs
 
Node.js
Node.jsNode.js
Node.js
 
Node.js and How JavaScript is Changing Server Programming
Node.js and How JavaScript is Changing Server Programming  Node.js and How JavaScript is Changing Server Programming
Node.js and How JavaScript is Changing Server Programming
 
Node js presentation
Node js presentationNode js presentation
Node js presentation
 
Introduction to Node.js
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.js
 
RESTful API In Node Js using Express
RESTful API In Node Js using Express RESTful API In Node Js using Express
RESTful API In Node Js using Express
 
Node.js, for architects - OpenSlava 2013
Node.js, for architects - OpenSlava 2013Node.js, for architects - OpenSlava 2013
Node.js, for architects - OpenSlava 2013
 
NodeJS - Server Side JS
NodeJS - Server Side JS NodeJS - Server Side JS
NodeJS - Server Side JS
 
Node.js - A Quick Tour
Node.js - A Quick TourNode.js - A Quick Tour
Node.js - A Quick Tour
 
node.js: Javascript's in your backend
node.js: Javascript's in your backendnode.js: Javascript's in your backend
node.js: Javascript's in your backend
 
Node Architecture and Getting Started with Express
Node Architecture and Getting Started with ExpressNode Architecture and Getting Started with Express
Node Architecture and Getting Started with Express
 
Complete MVC on NodeJS
Complete MVC on NodeJSComplete MVC on NodeJS
Complete MVC on NodeJS
 
All aboard the NodeJS Express
All aboard the NodeJS ExpressAll aboard the NodeJS Express
All aboard the NodeJS Express
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Use Node.js to create a REST API
Use Node.js to create a REST APIUse Node.js to create a REST API
Use Node.js to create a REST API
 
Non-blocking I/O, Event loops and node.js
Non-blocking I/O, Event loops and node.jsNon-blocking I/O, Event loops and node.js
Non-blocking I/O, Event loops and node.js
 
Comet with node.js and V8
Comet with node.js and V8Comet with node.js and V8
Comet with node.js and V8
 

Destaque

Anatomy of a Modern Node.js Application Architecture
Anatomy of a Modern Node.js Application Architecture Anatomy of a Modern Node.js Application Architecture
Anatomy of a Modern Node.js Application Architecture AppDynamics
 
Say No, Like a Boss! OSCON
Say No, Like a Boss! OSCONSay No, Like a Boss! OSCON
Say No, Like a Boss! OSCONfreedeb
 
OSCON Presentation: Developing High Performance Websites and Modern Apps with...
OSCON Presentation: Developing High Performance Websites and Modern Apps with...OSCON Presentation: Developing High Performance Websites and Modern Apps with...
OSCON Presentation: Developing High Performance Websites and Modern Apps with...Doris Chen
 
Angular 2.0: Getting ready
Angular 2.0: Getting readyAngular 2.0: Getting ready
Angular 2.0: Getting readyAxilis
 
Grunt JS - Getting Started With Grunt
Grunt JS - Getting Started With GruntGrunt JS - Getting Started With Grunt
Grunt JS - Getting Started With GruntDouglas Reynolds
 
Introduction to Node.js: perspectives from a Drupal dev
Introduction to Node.js: perspectives from a Drupal devIntroduction to Node.js: perspectives from a Drupal dev
Introduction to Node.js: perspectives from a Drupal devmcantelon
 
Grunt - The JavaScript Task Runner
Grunt - The JavaScript Task RunnerGrunt - The JavaScript Task Runner
Grunt - The JavaScript Task RunnerMohammed Arif
 
Building servers with Node.js
Building servers with Node.jsBuilding servers with Node.js
Building servers with Node.jsConFoo
 
Node.js ― Hello, world! の1歩先へ。
Node.js ― Hello, world! の1歩先へ。Node.js ― Hello, world! の1歩先へ。
Node.js ― Hello, world! の1歩先へ。Tatsuya Tobioka
 
Scaling and securing node.js apps
Scaling and securing node.js appsScaling and securing node.js apps
Scaling and securing node.js appsMaciej Lasyk
 
Building web apps with node.js, socket.io, knockout.js and zombie.js - Codemo...
Building web apps with node.js, socket.io, knockout.js and zombie.js - Codemo...Building web apps with node.js, socket.io, knockout.js and zombie.js - Codemo...
Building web apps with node.js, socket.io, knockout.js and zombie.js - Codemo...Ivan Loire
 
Introduction to Nodejs
Introduction to NodejsIntroduction to Nodejs
Introduction to NodejsGabriele Lana
 
Fullstack End-to-end test automation with Node.js, one year later
Fullstack End-to-end test automation with Node.js, one year laterFullstack End-to-end test automation with Node.js, one year later
Fullstack End-to-end test automation with Node.js, one year laterMek Srunyu Stittri
 
Node.js and Selenium Webdriver, a journey from the Java side
Node.js and Selenium Webdriver, a journey from the Java sideNode.js and Selenium Webdriver, a journey from the Java side
Node.js and Selenium Webdriver, a journey from the Java sideMek Srunyu Stittri
 
Architecting large Node.js applications
Architecting large Node.js applicationsArchitecting large Node.js applications
Architecting large Node.js applicationsSergi Mansilla
 
Modern UI Development With Node.js
Modern UI Development With Node.jsModern UI Development With Node.js
Modern UI Development With Node.jsRyan Anklam
 
Map, Flatmap and Reduce are Your New Best Friends: Simpler Collections, Concu...
Map, Flatmap and Reduce are Your New Best Friends: Simpler Collections, Concu...Map, Flatmap and Reduce are Your New Best Friends: Simpler Collections, Concu...
Map, Flatmap and Reduce are Your New Best Friends: Simpler Collections, Concu...Chris Richardson
 
OSCON 2013: Turing's Curse
OSCON 2013: Turing's CurseOSCON 2013: Turing's Curse
OSCON 2013: Turing's CurseCloudflare
 
Getting Started With Grunt for WordPress Development
Getting Started With Grunt for WordPress DevelopmentGetting Started With Grunt for WordPress Development
Getting Started With Grunt for WordPress DevelopmentDavid Bisset
 

Destaque (20)

Anatomy of a Modern Node.js Application Architecture
Anatomy of a Modern Node.js Application Architecture Anatomy of a Modern Node.js Application Architecture
Anatomy of a Modern Node.js Application Architecture
 
Say No, Like a Boss! OSCON
Say No, Like a Boss! OSCONSay No, Like a Boss! OSCON
Say No, Like a Boss! OSCON
 
OSCON Presentation: Developing High Performance Websites and Modern Apps with...
OSCON Presentation: Developing High Performance Websites and Modern Apps with...OSCON Presentation: Developing High Performance Websites and Modern Apps with...
OSCON Presentation: Developing High Performance Websites and Modern Apps with...
 
Angular 2.0: Getting ready
Angular 2.0: Getting readyAngular 2.0: Getting ready
Angular 2.0: Getting ready
 
Grunt JS - Getting Started With Grunt
Grunt JS - Getting Started With GruntGrunt JS - Getting Started With Grunt
Grunt JS - Getting Started With Grunt
 
Introduction to Node.js: perspectives from a Drupal dev
Introduction to Node.js: perspectives from a Drupal devIntroduction to Node.js: perspectives from a Drupal dev
Introduction to Node.js: perspectives from a Drupal dev
 
Grunt - The JavaScript Task Runner
Grunt - The JavaScript Task RunnerGrunt - The JavaScript Task Runner
Grunt - The JavaScript Task Runner
 
Building servers with Node.js
Building servers with Node.jsBuilding servers with Node.js
Building servers with Node.js
 
Node.js ― Hello, world! の1歩先へ。
Node.js ― Hello, world! の1歩先へ。Node.js ― Hello, world! の1歩先へ。
Node.js ― Hello, world! の1歩先へ。
 
Scaling and securing node.js apps
Scaling and securing node.js appsScaling and securing node.js apps
Scaling and securing node.js apps
 
Building web apps with node.js, socket.io, knockout.js and zombie.js - Codemo...
Building web apps with node.js, socket.io, knockout.js and zombie.js - Codemo...Building web apps with node.js, socket.io, knockout.js and zombie.js - Codemo...
Building web apps with node.js, socket.io, knockout.js and zombie.js - Codemo...
 
Node.js security
Node.js securityNode.js security
Node.js security
 
Introduction to Nodejs
Introduction to NodejsIntroduction to Nodejs
Introduction to Nodejs
 
Fullstack End-to-end test automation with Node.js, one year later
Fullstack End-to-end test automation with Node.js, one year laterFullstack End-to-end test automation with Node.js, one year later
Fullstack End-to-end test automation with Node.js, one year later
 
Node.js and Selenium Webdriver, a journey from the Java side
Node.js and Selenium Webdriver, a journey from the Java sideNode.js and Selenium Webdriver, a journey from the Java side
Node.js and Selenium Webdriver, a journey from the Java side
 
Architecting large Node.js applications
Architecting large Node.js applicationsArchitecting large Node.js applications
Architecting large Node.js applications
 
Modern UI Development With Node.js
Modern UI Development With Node.jsModern UI Development With Node.js
Modern UI Development With Node.js
 
Map, Flatmap and Reduce are Your New Best Friends: Simpler Collections, Concu...
Map, Flatmap and Reduce are Your New Best Friends: Simpler Collections, Concu...Map, Flatmap and Reduce are Your New Best Friends: Simpler Collections, Concu...
Map, Flatmap and Reduce are Your New Best Friends: Simpler Collections, Concu...
 
OSCON 2013: Turing's Curse
OSCON 2013: Turing's CurseOSCON 2013: Turing's Curse
OSCON 2013: Turing's Curse
 
Getting Started With Grunt for WordPress Development
Getting Started With Grunt for WordPress DevelopmentGetting Started With Grunt for WordPress Development
Getting Started With Grunt for WordPress Development
 

Semelhante a Node.js Patterns for Discerning Developers

Practical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.jsPractical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.jsasync_io
 
Intro To Node.js
Intro To Node.jsIntro To Node.js
Intro To Node.jsChris Cowan
 
TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...bobmcwhirter
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch
 
Introducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.jsIntroducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.jsRichard Rodger
 
Node.js: The What, The How and The When
Node.js: The What, The How and The WhenNode.js: The What, The How and The When
Node.js: The What, The How and The WhenFITC
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing UpDavid Padbury
 
Introduction to REST API with Node.js
Introduction to REST API with Node.jsIntroduction to REST API with Node.js
Introduction to REST API with Node.jsYoann Gotthilf
 
Why Nodejs Guilin Shanghai
Why Nodejs Guilin ShanghaiWhy Nodejs Guilin Shanghai
Why Nodejs Guilin ShanghaiJackson Tian
 
Why Node.js
Why Node.jsWhy Node.js
Why Node.jsguileen
 
Intro to node and mongodb 1
Intro to node and mongodb   1Intro to node and mongodb   1
Intro to node and mongodb 1Mohammad Qureshi
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011Nick Sieger
 
Parse cloud code
Parse cloud codeParse cloud code
Parse cloud code維佋 唐
 
Module, AMD, RequireJS
Module, AMD, RequireJSModule, AMD, RequireJS
Module, AMD, RequireJS偉格 高
 
Node js
Node jsNode js
Node jshazzaz
 
iPhone development from a Java perspective (Jazoon '09)
iPhone development from a Java perspective (Jazoon '09)iPhone development from a Java perspective (Jazoon '09)
iPhone development from a Java perspective (Jazoon '09)Netcetera
 
MFF UK - Introduction to iOS
MFF UK - Introduction to iOSMFF UK - Introduction to iOS
MFF UK - Introduction to iOSPetr Dvorak
 

Semelhante a Node.js Patterns for Discerning Developers (20)

Practical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.jsPractical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.js
 
Intro To Node.js
Intro To Node.jsIntro To Node.js
Intro To Node.js
 
TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.js
 
Introducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.jsIntroducing the Seneca MVP framework for Node.js
Introducing the Seneca MVP framework for Node.js
 
20120816 nodejsdublin
20120816 nodejsdublin20120816 nodejsdublin
20120816 nodejsdublin
 
Node.js: The What, The How and The When
Node.js: The What, The How and The WhenNode.js: The What, The How and The When
Node.js: The What, The How and The When
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
 
Introduction to REST API with Node.js
Introduction to REST API with Node.jsIntroduction to REST API with Node.js
Introduction to REST API with Node.js
 
Why Nodejs Guilin Shanghai
Why Nodejs Guilin ShanghaiWhy Nodejs Guilin Shanghai
Why Nodejs Guilin Shanghai
 
Why Node.js
Why Node.jsWhy Node.js
Why Node.js
 
Intro to node and mongodb 1
Intro to node and mongodb   1Intro to node and mongodb   1
Intro to node and mongodb 1
 
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
 
Parse cloud code
Parse cloud codeParse cloud code
Parse cloud code
 
NodeJS
NodeJSNodeJS
NodeJS
 
Module, AMD, RequireJS
Module, AMD, RequireJSModule, AMD, RequireJS
Module, AMD, RequireJS
 
Node js
Node jsNode js
Node js
 
Node azure
Node azureNode azure
Node azure
 
iPhone development from a Java perspective (Jazoon '09)
iPhone development from a Java perspective (Jazoon '09)iPhone development from a Java perspective (Jazoon '09)
iPhone development from a Java perspective (Jazoon '09)
 
MFF UK - Introduction to iOS
MFF UK - Introduction to iOSMFF UK - Introduction to iOS
MFF UK - Introduction to iOS
 

Mais de cacois

Devopssecfail
DevopssecfailDevopssecfail
Devopssecfailcacois
 
Machine Learning for Modern Developers
Machine Learning for Modern DevelopersMachine Learning for Modern Developers
Machine Learning for Modern Developerscacois
 
Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jscacois
 
Hadoop: The elephant in the room
Hadoop: The elephant in the roomHadoop: The elephant in the room
Hadoop: The elephant in the roomcacois
 
High-Volume Data Collection and Real Time Analytics Using Redis
High-Volume Data Collection and Real Time Analytics Using RedisHigh-Volume Data Collection and Real Time Analytics Using Redis
High-Volume Data Collection and Real Time Analytics Using Rediscacois
 
Automate your Development Environments with Vagrant
Automate your Development Environments with VagrantAutomate your Development Environments with Vagrant
Automate your Development Environments with Vagrantcacois
 
Node.js: A Guided Tour
Node.js: A Guided TourNode.js: A Guided Tour
Node.js: A Guided Tourcacois
 

Mais de cacois (7)

Devopssecfail
DevopssecfailDevopssecfail
Devopssecfail
 
Machine Learning for Modern Developers
Machine Learning for Modern DevelopersMachine Learning for Modern Developers
Machine Learning for Modern Developers
 
Avoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.jsAvoiding Callback Hell with Async.js
Avoiding Callback Hell with Async.js
 
Hadoop: The elephant in the room
Hadoop: The elephant in the roomHadoop: The elephant in the room
Hadoop: The elephant in the room
 
High-Volume Data Collection and Real Time Analytics Using Redis
High-Volume Data Collection and Real Time Analytics Using RedisHigh-Volume Data Collection and Real Time Analytics Using Redis
High-Volume Data Collection and Real Time Analytics Using Redis
 
Automate your Development Environments with Vagrant
Automate your Development Environments with VagrantAutomate your Development Environments with Vagrant
Automate your Development Environments with Vagrant
 
Node.js: A Guided Tour
Node.js: A Guided TourNode.js: A Guided Tour
Node.js: A Guided Tour
 

Último

Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 

Último (20)

Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 

Node.js Patterns for Discerning Developers

  • 1. Node.js Patterns For the Discerning Developer C. Aaron Cois, Ph.D. :: Carnegie Mellon University, SEI
  • 2. Me @aaroncois www.codehenge.net github.com/cacois Disclaimer: Though I am an employee of the Software Engineering Institute at Carnegie Mellon University, this work was not funded by the SEI and does not reflect the work or opinions of the SEI or its customers.
  • 4. Node.js Basics • JavaScript • Asynchronous • Non-blocking I/O • Event-driven
  • 7. Prototype-based Programming • JavaScript has no classes • Instead, functions define objects function Person() {} var p = new Person(); Image: http://tech2.in.com/features/gaming/five-wacky-gaming-hardware-to-look-forward-to/315742 Prototype
  • 8. Classless Programming What do classes do for us? • Define local scope / namespace • Allow private attributes / methods • Encapsulate code • Organize applications in an object-oriented way
  • 9. Prototype-based Programming function Person(firstname, lastname){ this.firstname = firstname; this.lastname = lastname; } var p = new Person(“Philip”, “Fry”); What else can do that?
  • 10. Prototype Inheritance function Person(firstname, lastname){ this.firstname = firstname; this.lastname = lastname; } // Create new class Employee = Person;//Inherit from superclass Employee.prototype = { marital_status: 'single', salute: function() { return 'My name is ' + this.firstname; } } var p = new Employee (“Philip”, “Fry”);
  • 11. Watch out! function Person(firstname, lastname){ this.firstname = firstname; this.lastname = lastname; } // Create new class Employee = Person;//Inherit from superclass Employee.prototype = { marital_status: 'single', salute: function() { return 'My name is ' + this.firstname; } } var p = new Employee (“Philip”, “Fry”); The ‘new’ is very important! If you forget, your new object will have global scope internally
  • 12. Another option function Person(firstname, lastname){ this.firstname = firstname; this.lastname = lastname; } Employee = Person;//Inherit from superclass Employee.prototype = { marital_status: 'single', salute: function() { return 'My name is ' + this.firstname; } } var p = Object.create(Employee); p.firstname = 'Philip'; p.lastname = 'Fry'; Works, but you can’t initialize attributes in constructor
  • 13. Anti-Pattern: JavaScript Imports • Spread code around files • Link libraries • No way to maintain private local scope/state/namespace • Leads to: – Name collisions – Unnecessary access
  • 14. Pattern: Modules • An elegant way of encapsulating and reusing code • Adapted from YUI, a few years before Node.js • Takes advantage of the anonymous closure features of JavaScript Image: http://wallpapersus.com/
  • 15. Modules in the Wild var http = require('http'), io = require('socket.io'), _ = require('underscore'); If you’ve programmed in Node, this looks familiar
  • 16. Anatomy of a module var privateVal = 'I am Private!'; module.exports = { answer: 42, add: function(x, y) { return x + y; } } mymodule.js
  • 17. Usage mod = require('./mymodule'); console.log('The answer: '+ mod.answer); var sum = mod.add(4,5); console.log('Sum: ' + sum);
  • 18. Modules are used everywhere // User model var mongoose = require('mongoose') , Schema = mongoose.Schema; var userSchema = new Schema({ name: {type: String, required: true}, email: {type: String, required: true}, githubid: String, twitterid: String, dateCreated: {type: Date, default: Date.now} }); userSchema.methods.validPassword = function validPass(pass) { // validate password… } module.exports = mongoose.model('User', userSchema);
  • 19. My config files? Modules. var config = require('config.js'); console.log('Configured user is: ' + config.user); module.exports = { user: 'maurice.moss' } config.js app.js
  • 21. Asynchronous Programming • Node is entirely asynchronous • You have to think a bit differently • Failure to understand the event loop and I/O model can lead to anti-patterns
  • 23. Event Loop Node.js Event Loop Node apps pass async tasks to the event loop, along with a callback (function, callback) Node app
  • 24. Event Loop Node.js Event Loop The event loop efficiently manages a thread pool and executes tasks efficiently… Thread 1 Thread 2 Thread n … Task 1 Task 2 Task 3 Task 4 Return 1 Callback1() …and executes each callback as tasks complete Node app
  • 25. Async I/O The following tasks should be done asynchronously, using the event loop: • I/O operations • Heavy computation • Anything requiring blocking
  • 26. Your Node app is single-threaded
  • 27. Anti-pattern: Synchronous Code for (var i = 0; i < 100000; i++){ // Do anything } Your app only has one thread, so: …will bring your app to a grinding halt
  • 28. Anti-pattern: Synchronous Code But why would you do that? Good question. But in other languages (Python), you may do this: for file in files: f = open(file, ‘r’) print f.readline()
  • 29. Anti-pattern: Synchronous Code The Node.js equivalent is: Based on examples from: https://github.com/nodebits/distilled-patterns/ var fs = require('fs'); for (var i = 0; i < files.length; i++){ data = fs.readFileSync(files[i]); console.log(data); } …and it will cause severe performance problems
  • 30. Pattern: Async I/O fs = require('fs'); fs.readFile('f1.txt','utf8',function(err,data){ if (err) { // handle error } console.log(data); });
  • 31. Async I/O fs = require('fs'); fs.readFile('f1.txt','utf8',function(err,data){ if (err) { // handle error } console.log(data); }); Anonymous, inline callback
  • 32. Async I/O fs = require('fs'); fs.readFile('f1.txt','utf8', function(err,data){ if (err) { // handle error } console.log(data); } ); Equivalent syntax
  • 33. Callback Hell When working with callbacks, nesting can get quite out of hand…
  • 34. Callback Hell var db = require('somedatabaseprovider'); //get recent posts http.get('/recentposts', function(req, res) { // open database connection db.openConnection('host', creds,function(err, conn){ res.param['posts'].forEach(post) { conn.query('select * from users where id='+post['user'],function(err,users){ conn.close(); res.send(users[0]); }); } }); });
  • 35. Callback Hell var db = require('somedatabaseprovider'); //get recent posts http.get('/recentposts', function(req, res) { // open database connection db.openConnection('host', creds,function(err, conn){ res.param['posts'].forEach(post) { conn.query('select * from users where id='+post['user'],function(err,users){ conn.close(); res.send(users[0]); }); } }); }); Get recent posts from web service API
  • 36. Callback Hell var db = require('somedatabaseprovider'); //get recent posts http.get('/recentposts', function(req, res) { // open database connection db.openConnection('host', creds,function(err, conn){ res.param['posts'].forEach(post) { conn.query('select * from users where id='+post['user'],function(err,users){ conn.close(); res.send(users[0]); }); } }); }); Open connection to DB
  • 37. Callback Hell var db = require('somedatabaseprovider'); //get recent posts http.get('/recentposts', function(req, res) { // open database connection db.openConnection('host', creds,function(err, conn){ res.param['posts'].forEach(post) { conn.query('select * from users where id='+post['user'],function(err,users){ conn.close(); res.send(users[0]); }); } }); }); Get user from DB for each post
  • 38. Callback Hell var db = require('somedatabaseprovider'); //get recent posts http.get('/recentposts', function(req, res) { // open database connection db.openConnection('host', creds,function(err, conn){ res.param['posts'].forEach(post) { conn.query('select * from users where id='+post['user'],function(err,users){ conn.close(); res.send(users[0]); }); } }); }); Return users
  • 39. Callback Hell var db = require('somedatabaseprovider'); //get recent posts http.get('/recentposts', function(req, res) { // open database connection db.openConnection('host', creds,function(err, conn){ res.param['posts'].forEach(post) { conn.query('select * from users where id='+post['user'],function(err,users){ conn.close(); res.send(users[0]); }); } }); });
  • 40. Anti-Pattern: Callback Hell fs.readdir(source, function(err, files) { if (err) { console.log('Error finding files: ' + err) } else { files.forEach(function(filename, fileIndex) { console.log(filename) gm(source + filename).size(function(err, values) { if (err) { console.log('Error identifying file size: ' + err) } else { console.log(filename + ' : ' + values) aspect = (values.width / values.height) widths.forEach(function(width, widthIndex) { height = Math.round(width / aspect) console.log('resizing ' + filename + 'to ' + height + 'x' + height) this.resize(width, height).write(destination+'w’+width+'_’+filename, function(err){ if (err) console.log('Error writing file: ' + err) }) }.bind(this)) } }) }) } }) http://callbackhell.com/
  • 41. Solutions • Separate anonymous callback functions (cosmetic) • Async.js • Promises • Generators
  • 42. Pattern: Separate Callbacks fs = require('fs'); callback = function(err,data){ if (err) { // handle error } console.log(data); } fs.readFile('f1.txt','utf8',callback);
  • 43. Can Turn This var db = require('somedatabaseprovider'); http.get('/recentposts', function(req, res){ db.openConnection('host', creds, function(err, conn){ res.param['posts'].forEach(post) { conn.query('select * from users where id=' + post['user'],function(err,results){ conn.close(); res.send(results[0]); }); } }); });
  • 44. Into This var db = require('somedatabaseprovider'); http.get('/recentposts', afterRecentPosts); function afterRecentPosts(req, res) { db.openConnection('host', creds, function(err, conn) { afterDBConnected(res, conn); }); } function afterDBConnected(err, conn) { res.param['posts'].forEach(post) { conn.query('select * from users where id='+post['user'],afterQuery); } } function afterQuery(err, results) { conn.close(); res.send(results[0]); }
  • 45. This is really a Control Flow issue
  • 46. Pattern: Async.js Async.js provides common patterns for async code control flow https://github.com/caolan/async Also provides some common functional programming paradigms
  • 47. Serial/Parallel Functions • Sometimes you have linear serial/parallel computations to run, without branching callback growth Function 1 Function 2 Function 3 Function 4 Function 1 Function 2 Function 3 Function 4
  • 48. Serial/Parallel Functions async.parallel([ function(){ ... }, function(){ ... } ], callback); async.series([ function(){ ... }, function(){ ... } ]);
  • 49. Serial/Parallel Functions async.parallel([ function(){ ... }, function(){ ... } ], callback); async.series([ function(){ ... }, function(){ ... } ], callback); Single Callback
  • 50. Waterfall Async.waterfall([ function(callback){ ... }, function(input,callback){ ... }, function(input,callback){ ... }, ], callback);
  • 51. Map var arr = ['file1','file2','file3']; async.map(arr, fs.stat, function(err, results){ // results is an array of stats for each file console.log('File stats: ' + JSON.stringify(results)); });
  • 52. Filter var arr = ['file1','file2','file3']; async.filter(arr, fs.exists, function(results){ // results is a list of the existing files console.log('Existing files: ' + results); });
  • 54. Carefree var fs = require('fs'); for (var i = 0; i < 10000; i++) { fs.readFileSync(filename); } With synchronous code, you can loop as much as you want: The file is opened once each iteration. This works, but is slow and defeats the point of Node.
  • 55. Synchronous Doesn’t Scale What if we want to scale to 10,000+ concurrent users? File I/O becomes the bottleneck Users get in a long line
  • 56. Async to the Rescue var fs = require('fs'); function onRead(err, file) { if (err) throw err; } for (var i = 0; i < 10000; i++) { fs.readFile(filename, onRead); } What happens if I do this asyncronously?
  • 57. Ruh Roh The event loop is fast This will open the file 10,000 times at once This is unnecessary…and on most systems, you will run out of file descriptors!
  • 58. Pattern: The Request Batch • One solution is to batch requests • Piggyback on existing requests for the same file • Each file then only has one open request at a time, regardless of requesting clients
  • 59. // Batching wrapper for fs.readFile() var requestBatches = {}; function batchedReadFile(filename, callback) { // Is there already a batch for this file? if (filename in requestBatches) { // if so, push callback into batch requestBatches[filename].push(callback); return; } // If not, start a new request var callbacks = requestBatches[filename] = [callback]; fs.readFile(filename, onRead); // Flush out the batch on complete function onRead(err, file) { delete requestBatches[filename]; for(var i = 0;i < callbacks.length; i++) { // execute callback, passing arguments along callbacks[i](err, file); } } } Based on examples from: https://github.com/nodebits/distilled-patterns/
  • 60. // Batching wrapper for fs.readFile() var requestBatches = {}; function batchedReadFile(filename, callback) { // Is there already a batch for this file? if (filename in requestBatches) { // if so, push callback into batch requestBatches[filename].push(callback); return; } // If not, start a new request var callbacks = requestBatches[filename] = [callback]; fs.readFile(filename, onRead); // Flush out the batch on complete function onRead(err, file) { delete requestBatches[filename]; for(var i = 0;i < callbacks.length; i++) { // execute callback, passing arguments along callbacks[i](err, file); } } } Based on examples from: https://github.com/nodebits/distilled-patterns/ Is this file already being read?
  • 61. // Batching wrapper for fs.readFile() var requestBatches = {}; function batchedReadFile(filename, callback) { // Is there already a batch for this file? if (filename in requestBatches) { // if so, push callback into batch requestBatches[filename].push(callback); return; } // If not, start a new request var callbacks = requestBatches[filename] = [callback]; fs.readFile(filename, onRead); // Flush out the batch on complete function onRead(err, file) { delete requestBatches[filename]; for(var i = 0;i < callbacks.length; i++) { // execute callback, passing arguments along callbacks[i](err, file); } } } Based on examples from: https://github.com/nodebits/distilled-patterns/ If not, start a new file read operation
  • 62. // Batching wrapper for fs.readFile() var requestBatches = {}; function batchedReadFile(filename, callback) { // Is there already a batch for this file? if (filename in requestBatches) { // if so, push callback into batch requestBatches[filename].push(callback); return; } // If not, start a new request var callbacks = requestBatches[filename] = [callback]; fs.readFile(filename, onRead); // Flush out the batch on complete function onRead(err, file) { delete requestBatches[filename]; for(var i = 0;i < callbacks.length; i++) { // execute callback, passing arguments along callbacks[i](err, file); } } } Based on examples from: https://github.com/nodebits/distilled-patterns/ When read finished, return to all requests
  • 63. Usage //Request the resource 10,000 times at once for (var i = 0; i < 10000; i++) { batchedReadFile(file, onComplete); } function onComplete(err, file) { if (err) throw err; else console.log('File contents: ' + file); } Based on examples from: https://github.com/nodebits/distilled-patterns/
  • 64. Pattern: The Request Batch This pattern is effective on many read-type operations, not just file reads Example: also good for web service API calls
  • 65. Shortcomings Batching requests is great for high request spikes Often, you are more likely to see steady requests for the same resource This begs for a caching solution
  • 66. Pattern: Request Cache Let’s try a simple cache Persist the result forever and check for new requests for same resource
  • 67. // Caching wrapper around fs.readFile() var requestCache = {}; function cachingReadFile(filename, callback) { //Do we have resource in cache? if (filename in requestCache) { var value = requestCache[filename]; // Async behavior: delay result till next tick process.nextTick(function () { callback(null, value); }); return; } // If not, start a new request fs.readFile(filename, onRead); // Cache the result if there is no error function onRead(err, contents) { if (!err) requestCache[filename] = contents; callback(err, contents); } } Based on examples from: https://github.com/nodebits/distilled-patterns/
  • 68. Usage // Request the file 10,000 times in series // Note: for serial requests we need to iterate // with callbacks, rather than within a loop var its = 10000; cachingReadFile(file, next); function next(err, contents) { console.log('File contents: ' + contents); if (!(its--)) return; cachingReadFile(file, next); } Based on examples from: https://github.com/nodebits/distilled-patterns/
  • 69. Almost There! You’ll notice two issues with the Request Cache as presented: • Concurrent requests are an issue again • Cache invalidation not handled Let’s combine cache and batch strategies:
  • 70. // Wrapper for both caching and batching of requests var requestBatches = {}, requestCache = {}; function readFile(filename, callback) { if (filename in requestCache) { // Do we have resource in cache? var value = requestCache[filename]; // Delay result till next tick to act async process.nextTick(function () { callback(null, value); }); return; } if (filename in requestBatches) {// Else, does file have a batch? requestBatches[filename].push(callback); return; } // If neither, create new batch and request var callbacks = requestBatches[filename] = [callback]; fs.readFile(filename, onRead); // Cache the result and flush batch function onRead(err, file) { if (!err) requestCache[filename] = file; delete requestBatches[filename]; for (var i=0;i<callbacks.length;i++) { callbacks[i](err, file); } } } Based on examples from: https://github.com/nodebits/distilled-patterns/
  • 71. scale-fs I wrote a module for scalable File I/O https://www.npmjs.org/package/scale-fs Usage: var fs = require(’scale-fs'); for (var i = 0; i < 10000; i++) { fs.readFile(filename); }
  • 72. Final Thoughts Most anti-patterns in Node.js come from: • Sketchy JavaScript heritage • Inexperience with Asynchronous Thinking Remember, let the Event Loop do the heavy lifting!
  • 73. Thanks Code samples from this talk at: https://github.com/cacois/node- patterns-discerning
  • 74. Disclaimer Though I am an employee of the Software Engineering Institute at Carnegie Mellon University, this wok was not funded by the SEI and does not reflect the work or opinions of the SEI or its customers.
  • 76. Node.js Event Loop The event loop efficiently manages a thread pool and executes tasks efficiently… Thread 1 Thread 2 Thread n … Task 1 Task 2 Task 3 Task 4 Return 1 Callback1() …and executes each callback as tasks complete Node.js app Node apps pass async tasks to the event loop, along with a callback (function, callback) 1 2 3

Notas do Editor

  1. Images from http://wallpapersus.com/
  2. Note: enumerable is not set to true by default for inherited attributes. You can change this, but its often not worth it
  3. New in ecmascript 5. Problem: you can’t pass in constructor attributes within Object.create.
  4. What happens when we add error handling?
  5. Callback contains an object filled with results from each function
  6. Each function gets input from the last function
  7. Map returns an array of RESULTS, one for each input object/value
  8. Map returns a sub-array of objects/values form the input array, filtered by a boolean test function