SlideShare a Scribd company logo
Asynchronous 
programming 
done right. 
Without race conditions ..ions ..io on 
..ns ditions. 
by Piotr Pelczar (Athlan)
Asynchronous programming done right - Node.js
About me 
Piotr Pelczar 
Freelancer for 8yrs 
PHP, Node.js, Java/Groovy 
Zend Certified Engineer 
IPIJ, Startups
Stay in touch 
athlan.pl 
me@athlan.pl 
facebook.com/piotr.pelczar 
github.com/athlan 
slideshare.net/piotrpelczar 
linkedin.com/in/ppelczar
Asynchronous 
programming 
Asynchronous actions are actions executed in a non-blocking 
scheme, allowing the main program flow to continue processing.
How software lives in 
hardware? 
Operating systems are process based 
Each process has assigned processor, registers, memory
How software lives in 
hardware? 
Process paralelism using threads (thread pools) 
Switching processor over processes/threads causes context 
switching
1. context switching = wasting time
Sync programming 
In trivial, sequential approach 
Each operation is executed sequentially: 
O(t) > O(t+1) 
if O(t) stucks, O(t+1) waits...
Sync programming
This is cool, software flow is predictible 
But not in high throughput I/O 
I/O costs because of waiting time...
High throughput I/O 
High throughput I/O doesn't mean: 
Memory operations 
Fast single-thread computing
High throughput I/O 
High throughput I/O means: 
HTTP requests 
Database connections 
Queue system dispatching 
HDD operations
2. Avoid I/O blocking
2. Avoid I/O blocking
Single-threaded, event loop 
model 
Imagine a man, who has a task: 
Walk around 
When bucket is full of water, just pour another bucket 
Go to next bucket
There is no sequences 
In async programming, results appears in no sequences 
operation1(); // will output "operation1 finished." 
operation2(); // will output "operation2 finished." 
operation3(); // will output "operation3 finished."
There is no sequences 
operation1() would be 
var amqp = require("amqp") 
var eventbus = amqp.createConnection(); 
console.log("AMQP connecting..."); 
eventbus.on("ready", function() { 
console.log("AMQP connected..."); 
callback(); 
return; 
});
There is no sequences 
operation2() would be 
var redis = require("redis") 
var conn = redis.createClient(port, host, options); 
console.log("Redis connecting..."); 
conn.auth(pass, function(err) { 
if(err) 
console.log("Redis failed..."); 
else 
console.log("Redis connected..."); 
callback(); 
return; 
});
There is no sequences 
operation3() would be 
var mongojs = require("mongojs"); 
console.log("Mongo connecting..."); 
var conn = mongojs.connect(connectionString); // blocking operation 
console.log("Mongo connected..."); 
callback(); 
return;
There is no sequences 
Expectations? 
AMQP connecting... // operation1() 
AMQP connected... // operation1() 
Redis connecting... // operation2() 
Redis failed... // operation2() 
Mongo connecting... // operation3(), blocking 
Mongo connected... // operation3()
There is no sequences 
Expectations?
There is no sequences 
The result: 
AMQP connecting... // operation1() 
Redis connecting... // operation2() 
Mongo connecting... // operation3(), blocking 
Mongo connected... // operation3() 
Redis failed... // operation2() 
AMQP connected... // operation1()
There is no sequences
So... what functions 
returns? 
You can perform future tasks in function, so what will be 
returned? 
value123 will be returned, 
function my_function() { 
operation1(); 
operation2(); 
operation3(); 
return "value123"; 
} 
just after blocking code, without waiting for non-blocking.
Assume: Functions does 
NOT returns values 
The function block is executed immedietally from top to bottom. 
You cannot rely to return value, because it is useless.
Callbacks 
Callback is the reference to function. 
var callbackFunction = function(result) { 
console.log("Result: %s", result) 
} 
When operation is done, the callback function is executed. 
callbackFunction("test1") // "Result: test1" will be printed out
Callbacks 
If callbackFunction is a variable (value = reference), 
so can be passed it via function argument. 
var callbackFunction = function() { ... } 
someOtherFunction(callbackFunction); 
function someOtherFunction(callback) { 
callback(); // execute function from argument 
}
Callbacks 
Functions can be defined as anonymous (closures) 
function someOtherFunction(callback) { 
var arg1 = "test"; 
callback(arg1); // execute function from argument 
} 
someOtherFunction(function(arg1) { 
console.log('done... %s', arg1); 
})
Callbacks can be nested 
Nesting callbacks makes code unreadeable: 
var amqp = require('amqp'); 
var connection = amqp.createConnection(); 
connection.on('ready', function() { 
connection.exchange("ex1", function(exchange) { 
connection.queue('queue1', function(q) { 
q.bind(exchange, 'r1'); 
q.subscribe(function(json, headers, info, m) { 
console.log("msg: " + JSON.stringify(json)); 
}); 
}); 
}); 
});
Callbacks can be nested 
Nesting callbacks makes code unreadeable: 
var amqp = require('amqp'); 
var connection = amqp.createConnection(); 
connection.on('ready', function() { 
connection.exchange("ex1", function(exchange) { 
connection.queue('queue1', function(q) { 
q.bind(exchange, 'r1'); 
q.subscribe(function(json, headers, info, m) { 
console.log("msg: " + JSON.stringify(json)); 
table.update(select, data, function() { 
table.find(select, function(err, rows) { 
// inserted rows... 
} 
}); 
}); 
}); 
}); 
});
Asynchronous control flows 
Promise design pattern 
Libraries that manages callbacks references
Promise design pattern 
1. Client fires function that will return result in the future 
in the future, so it is a promise 
2. Function returns promise object immedietaly 
before non-blocking operations 
3. Client registers callbacks 
4. Callbacks will be fired in the future, when task is done 
var resultPromise = loader.loadData(sourceFile) 
resultPromise(function success(data) { 
// this function will be called while operation will succeed 
}, function error(err) { 
// on fail 
})
Promise design pattern 
1. Create deferred object 
2. Return def.promise 
3. Call resolve() or reject() 
var loadData = function(sourceFile) { 
var def = deferred() 
, proc = process.spawn('java', ['-jar', 'loadData.jar', sourceFile]) 
var commandProcessBuff = null 
, commandProcessBuffError = null; 
proc.stdout.on('data', function (data) { commandProcessBuff += data }) 
proc.stderr.on('data', function (data) { commandProcessBuffError += data }) 
proc.on('close', function (code) { 
if(null !== commandProcessBuffError) 
def.reject(commandProcessBuffError) 
else 
def.resolve(commandProcessBuff) 
}) 
return def.promise 
}
Promise design pattern
Async Node.js library 
Provides control flows like: 
Sequences (series) 
Waterfalls (sequences with parameters passing) 
Parallel (with limit) 
Some/every conditions 
While/until 
Queue
Async Node.js library 
Series
Async Node.js library 
Series 
async.series([ 
function(callback) { 
// operation1 
}, 
function(callback) { 
// operation2 
}, 
function(callback) { 
// operation3 
} 
], function() { 
console.log('all operations done') 
})
Async Node.js library 
Parallel 
async.parallel([ 
function(callback) { 
// operation1 
}, 
function(callback) { 
// operation2 
}, 
function(callback) { 
// operation3 
} 
], function() { 
console.log('all operations done') 
})
Async Node.js library 
Parallel limit
Async Node.js library 
Parallel limit 
var tasks = [ 
function(callback) { 
// operation1 
}, 
function(callback) { 
// operation2 
}, 
// ... 
] 
async.parallelLimit(tasks, 2, function() { 
console.log('all operations done') 
})
Async Node.js library 
Waterfall 
async.waterfall([ 
function(callback) { 
// operation1 
callback(null, arg1, arg2) 
}, 
function(arg1, arg2, callback) { 
// operation2 
callback(null, foo, bar) 
}, 
function(foo, bar, callback) { 
// operation3 
} 
], function() { 
console.log('all operations done') 
})
Async Node.js library 
Whilst 
async.doWhilst( 
function(done) { 
// operation1 
done(null, arg1, arg2) 
}, 
function() { 
return pages < limit 
} 
], function() { 
console.log('done') 
})
Asynchronous 
programming traps 
Dealing with callbacks may be tricky. Keep your code clean.
Unnamed callbacks 
Keep your code clean, don't name callback function callback 
function doSomething(callback) { 
return callback; 
}
Unnamed callbacks 
function doSomething(callback) { 
doAnotherThing(function(callback2) { 
doYetAnotherThing(function(callback3) { 
return callback(); 
}) 
}) 
}
Unnamed callbacks 
Instead of this, name your callbacks 
function doSomething(done) { 
doAnotherThing(function(doneFetchingFromApi) { 
doYetAnotherThing(function(doneWritingToDatabase) { 
return done(); 
}) 
}) 
}
Double callbacks 
function doSomething(done) { 
doAnotherThing(function (err) { 
if (err) done(err); 
done(null, result); 
}); 
} 
Callback is fired twice!
Double callbacks 
Fix: Always prepend callback execution with return statement. 
function doSomething(done) { 
doAnotherThing(function (err) { 
if (err) 
return done(err); 
return done(null, result); 
}); 
} 
Normally, return ends function execution, why do not keep this 
rule while async.
Double callbacks 
Double callbacks are very hard to debug. 
The callback wrapper can be written and execute it only once. 
setTimeout(function() { 
done('a') 
}, 200) 
setTimeout(function() { 
done('b') 
}, 500)
Double callbacks 
var CallbackOnce = function(callback) { 
this.isFired = false 
this.callback = callback 
} 
CallbackOnce.prototype.create = function() { 
var delegate = this 
return function() { 
if(delegate.isFired) 
return 
delegate.isFired = true 
delegate.callback.apply(null, arguments) 
} 
}
Double callbacks 
obj1 = new CallbackOnce(done) 
// decorate callback 
safeDone = obj1.create() // safeDone() is proxy function that passes arguments 
setTimeout(function() { 
safeDone('a') // safe now... 
}, 200) 
setTimeout(function() { 
safeDone('b') // safe now... 
}, 500)
Unexpected callbacks 
Never fire callback until task is done. 
function doSomething(done) { 
doAnotherThing(function () { 
if (condition) { 
var result = null 
// prepare result... 
return done(result); 
} 
return done(null); 
}); 
} 
The ending return will be fired even if condition pass.
Unexpected callbacks 
Never fire callback until task is done. 
function doSomething(done) { 
doAnotherThing(function () { 
if (condition) { 
var result = null 
// prepare result... 
return done(result); 
} 
else { 
return done(null); 
} 
}); 
}
Unexpected callbacks 
Never use callback in try clause! 
function (callback) { 
another_function(function (err, some_data) { 
if (err) 
return callback(err); 
try { 
callback(null, JSON.parse(some_data)); // error here 
} catch(err) { 
callback(new Error(some_data + ' is not a valid JSON')); 
} 
}); 
} 
If callback throws an exception, then it is executed exactly twice!
Unexpected callbacks 
Never use callback in try clause! 
function (callback) { 
another_function(function (err, some_data) { 
if (err) 
return callback(err); 
try { 
var parsed = JSON.parse(some_data) 
} catch(err) { 
return callback(new Error(some_data + ' is not a valid JSON')); 
} 
callback(null, parsed); 
}); 
}
Unexpected callbacks 
Never use callback in try clause!
Take care of events 
Read docs carefully. Really. 
function doSomething(done) { 
var proc = process.spawn('java', ['-jar', 'loadData.jar', sourceFile]) 
var procBuff = ''; 
proc.stdout.on('data', function (data) { 
procBuff += data; 
}); 
// WAT?! 
proc.stderr.on('data', function (data) { 
done(new Error("An error occured: " + data)) 
}); 
proc.on('close', function (code) { 
done(null, procBuff); 
} 
}
Take care of events 
Read docs carefully. Really. 
function doSomething(done) { 
var proc = process.spawn('java', ['-jar', 'loadData.jar', sourceFile]) 
var procBuff = ''; 
var procBuffError = ''; 
proc.stdout.on('data', function (data) { 
procBuff += data; 
}); 
proc.stderr.on('data', function (data) { 
proc += data; 
}); 
proc.on('close', function (code) { 
if(code !== 0) { 
return done(new Error("An error occured: " + procBuffError)); 
} 
else { 
return done(null, procBuff) 
} 
} 
}
Unreadable and logs 
Keep in mind, that asynchronous logs will interweave 
There are not sequenced 
Or there will be same log strings
Unexpected callbacks 
Asynchronous logs will interweave
Unreadable and logs 
Logs without use context are useless... 
function getResults(keyword, done) { 
http.request(url, function(response) { 
console.log('Fetching from API') 
response.on('error', function(err) { 
console.log('API error') 
}) 
}); 
}
Unreadable and logs 
function getResults(keyword, done) { 
var logContext = { keyword: keyword } 
http.request(url, function(response) { 
console.log(logContext, 'Fetching from API') 
response.on('error', function(err) { 
console.log(logContext, 'API error') 
}) 
}); 
}
Unreadable and logs 
Centralize your logs - use logstash 
And make them searcheable - Elasticsearch + Kibana
Too many opened 
background-tasks 
While running parallel in order to satisfy first-better algorithm, 
others should be aborted
Too many opened 
background-tasks 
Provide cancellation API: 
var events = require('events') 
function getResults(keyword) { 
var def = deferred() 
var eventbus = new events.EventEmitter() 
var req = http.request(url, function(response) { 
var err = null 
, content = null 
res.on('data', function(chunk) { 
content += chunk; 
}); 
response.on('close', function() { 
if(err) 
return def.reject(err) 
else 
return def.resolve(content) 
}) 
response.on('error', function(err) { 
err += err 
}) 
});
Too many opened 
background-tasks 
Provide cancellation API: 
var response = getResults('test') 
response.result(function success() { 
// ... 
}, function error() { 
// ... 
}) 
// if we need 
response.events.emit('abort')
Everything runs in parallel except your code. 
When currently code is running, (not waiting for I/O descriptors) 
whole event loop is blocked.
THE END 
by Piotr Pelczar
Q&A 
by Piotr Pelczar

More Related Content

PDF
Callbacks, promises, generators - asynchronous javascript
Łukasz Kużyński
 
PPTX
Avoiding Callback Hell with Async.js
cacois
 
PPTX
Avoiding callback hell in Node js using promises
Ankit Agarwal
 
PDF
Understanding Asynchronous JavaScript
jnewmanux
 
PDF
Callbacks and control flow in Node js
Thomas Roch
 
PPTX
The Promised Land (in Angular)
Domenic Denicola
 
PDF
JavaScript Promise
Joseph Chiang
 
PDF
Javascript Promises/Q Library
async_io
 
Callbacks, promises, generators - asynchronous javascript
Łukasz Kużyński
 
Avoiding Callback Hell with Async.js
cacois
 
Avoiding callback hell in Node js using promises
Ankit Agarwal
 
Understanding Asynchronous JavaScript
jnewmanux
 
Callbacks and control flow in Node js
Thomas Roch
 
The Promised Land (in Angular)
Domenic Denicola
 
JavaScript Promise
Joseph Chiang
 
Javascript Promises/Q Library
async_io
 

What's hot (20)

PDF
$q and Promises in AngularJS
a_sharif
 
PDF
Promise pattern
Sebastiaan Deckers
 
PPTX
JavaScript Promises
L&T Technology Services Limited
 
PPTX
Promises, Promises
Domenic Denicola
 
PDF
JavaScript Promises
Tomasz Bak
 
PDF
Boom! Promises/A+ Was Born
Domenic Denicola
 
PPTX
Async Frontiers
Domenic Denicola
 
PDF
Asynchronous Programming FTW! 2 (with AnyEvent)
xSawyer
 
PPTX
Java Script Promise
Alok Guha
 
PDF
JavaScript Promises
Derek Willian Stavis
 
PDF
Practical JavaScript Promises
Asa Kusuma
 
PDF
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Islam Sharabash
 
PDF
Containers & Dependency in Ember.js
Matthew Beale
 
PDF
Avoiding callback hell with promises
TorontoNodeJS
 
PPTX
ES6 is Nigh
Domenic Denicola
 
PDF
Any event intro
qiang
 
PDF
Getting Comfortable with JS Promises
Asa Kusuma
 
PDF
Why Redux-Observable?
Anna Su
 
PPTX
Perl: Coro asynchronous
Shmuel Fomberg
 
PDF
How to send gzipped requests with boto3
Luciano Mammino
 
$q and Promises in AngularJS
a_sharif
 
Promise pattern
Sebastiaan Deckers
 
JavaScript Promises
L&T Technology Services Limited
 
Promises, Promises
Domenic Denicola
 
JavaScript Promises
Tomasz Bak
 
Boom! Promises/A+ Was Born
Domenic Denicola
 
Async Frontiers
Domenic Denicola
 
Asynchronous Programming FTW! 2 (with AnyEvent)
xSawyer
 
Java Script Promise
Alok Guha
 
JavaScript Promises
Derek Willian Stavis
 
Practical JavaScript Promises
Asa Kusuma
 
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Islam Sharabash
 
Containers & Dependency in Ember.js
Matthew Beale
 
Avoiding callback hell with promises
TorontoNodeJS
 
ES6 is Nigh
Domenic Denicola
 
Any event intro
qiang
 
Getting Comfortable with JS Promises
Asa Kusuma
 
Why Redux-Observable?
Anna Su
 
Perl: Coro asynchronous
Shmuel Fomberg
 
How to send gzipped requests with boto3
Luciano Mammino
 

Viewers also liked (20)

PDF
Soluciones tecnológicas para REA
Ricardo Corai
 
PPT
Implementación Repositorio De Objetos De Aprendizajes Basado En
f.cabrera1
 
PPT
Repositorio Institucional para el manejo de Investigaciones de la UNAN-Manag...
Departamento de Informática Educativa UNAN-Managua
 
PPTX
What is Node.js used for: The 2015 Node.js Overview Report
Gabor Nagy
 
KEY
groovy & grails - lecture 13
Alexandre Masselot
 
PPTX
Responsive Design
MRMtech
 
PPTX
Stack_Overflow-Network_Graph
Yaopeng (Gyoho) Wu
 
PDF
Presentacion MoodleMoot 2014 Colombia - Integración Moodle con un Repositorio...
Paola Amadeo
 
PPTX
Stack Overflow - It's all about performance / Marco Cecconi (Stack Overflow)
Ontico
 
PDF
Modern HTML & CSS Coding: Speed, Semantics & Structure
Raven Tools
 
PDF
NodeJS: the good parts? A skeptic’s view (oredev, oredev2013)
Chris Richardson
 
PPTX
StrongLoop Overview
Shubhra Kar
 
ZIP
Why Scala for Web 2.0?
Alex Payne
 
PDF
Curso avanzado de capacitación en DSpace
Servicio de Difusión de la Creación Intelectual (SEDICI)
 
PPTX
Html5 devconf nodejs_devops_shubhra
Shubhra Kar
 
PDF
Node.js Frameworks & Design Patterns Webinar
Shubhra Kar
 
PPTX
Webstock 2010 - Stack Overflow: Building Social Software for the Anti-Social
codinghorror
 
PDF
Toronto node js_meetup
Shubhra Kar
 
PPT
Introducing the New DSpace User Interface
Tim Donohue
 
PDF
Stack Overflow slides Data Analytics
Rahul Thankachan
 
Soluciones tecnológicas para REA
Ricardo Corai
 
Implementación Repositorio De Objetos De Aprendizajes Basado En
f.cabrera1
 
Repositorio Institucional para el manejo de Investigaciones de la UNAN-Manag...
Departamento de Informática Educativa UNAN-Managua
 
What is Node.js used for: The 2015 Node.js Overview Report
Gabor Nagy
 
groovy & grails - lecture 13
Alexandre Masselot
 
Responsive Design
MRMtech
 
Stack_Overflow-Network_Graph
Yaopeng (Gyoho) Wu
 
Presentacion MoodleMoot 2014 Colombia - Integración Moodle con un Repositorio...
Paola Amadeo
 
Stack Overflow - It's all about performance / Marco Cecconi (Stack Overflow)
Ontico
 
Modern HTML & CSS Coding: Speed, Semantics & Structure
Raven Tools
 
NodeJS: the good parts? A skeptic’s view (oredev, oredev2013)
Chris Richardson
 
StrongLoop Overview
Shubhra Kar
 
Why Scala for Web 2.0?
Alex Payne
 
Curso avanzado de capacitación en DSpace
Servicio de Difusión de la Creación Intelectual (SEDICI)
 
Html5 devconf nodejs_devops_shubhra
Shubhra Kar
 
Node.js Frameworks & Design Patterns Webinar
Shubhra Kar
 
Webstock 2010 - Stack Overflow: Building Social Software for the Anti-Social
codinghorror
 
Toronto node js_meetup
Shubhra Kar
 
Introducing the New DSpace User Interface
Tim Donohue
 
Stack Overflow slides Data Analytics
Rahul Thankachan
 

Similar to Asynchronous programming done right - Node.js (20)

PDF
The art of concurrent programming
Iskren Chernev
 
PDF
The evolution of asynchronous javascript
Alessandro Cinelli (cirpo)
 
PDF
Event Driven Javascript
Federico Galassi
 
PDF
JS Fest 2019 Node.js Antipatterns
Timur Shemsedinov
 
ODP
Node js
hazzaz
 
PDF
Asynchronous programming with java script and node.js
Timur Shemsedinov
 
PPTX
Async discussion 9_29_15
Cheryl Yaeger
 
ODP
Asynchronous I/O in NodeJS - new standard or challenges?
Dinh Pham
 
PDF
Node js
LearningTech
 
PDF
Event driven javascript
Francesca1980
 
PDF
Event driven javascript
Francesca1980
 
KEY
Playing With Fire - An Introduction to Node.js
Mike Hagedorn
 
PDF
Promise: async programming hero
The Software House
 
PDF
Asynchronous development in JavaScript
Amitai Barnea
 
PPTX
Node.js Patterns for Discerning Developers
cacois
 
PDF
Kamil witecki asynchronous, yet readable, code
Kamil Witecki
 
PDF
The Strange World of Javascript and all its little Asynchronous Beasts
Federico Galassi
 
PDF
Promises - Asynchronous Control Flow
Henrique Barcelos
 
PDF
Intro to Asynchronous Javascript
Garrett Welson
 
PDF
Douglas Crockford: Serversideness
WebExpo
 
The art of concurrent programming
Iskren Chernev
 
The evolution of asynchronous javascript
Alessandro Cinelli (cirpo)
 
Event Driven Javascript
Federico Galassi
 
JS Fest 2019 Node.js Antipatterns
Timur Shemsedinov
 
Node js
hazzaz
 
Asynchronous programming with java script and node.js
Timur Shemsedinov
 
Async discussion 9_29_15
Cheryl Yaeger
 
Asynchronous I/O in NodeJS - new standard or challenges?
Dinh Pham
 
Node js
LearningTech
 
Event driven javascript
Francesca1980
 
Event driven javascript
Francesca1980
 
Playing With Fire - An Introduction to Node.js
Mike Hagedorn
 
Promise: async programming hero
The Software House
 
Asynchronous development in JavaScript
Amitai Barnea
 
Node.js Patterns for Discerning Developers
cacois
 
Kamil witecki asynchronous, yet readable, code
Kamil Witecki
 
The Strange World of Javascript and all its little Asynchronous Beasts
Federico Galassi
 
Promises - Asynchronous Control Flow
Henrique Barcelos
 
Intro to Asynchronous Javascript
Garrett Welson
 
Douglas Crockford: Serversideness
WebExpo
 

More from Piotr Pelczar (7)

PDF
Pragmatic Monolith-First, easy to decompose, clean architecture
Piotr Pelczar
 
PDF
Elasticsearch - SEARCH & ANALYZE DATA IN REAL TIME
Piotr Pelczar
 
PPTX
[BDD] Introduction to Behat (PL)
Piotr Pelczar
 
PPTX
How NOT to write in Node.js
Piotr Pelczar
 
PPTX
Liquibase - database structure versioning
Piotr Pelczar
 
PPTX
CQRS
Piotr Pelczar
 
PPTX
Scalable Web Apps
Piotr Pelczar
 
Pragmatic Monolith-First, easy to decompose, clean architecture
Piotr Pelczar
 
Elasticsearch - SEARCH & ANALYZE DATA IN REAL TIME
Piotr Pelczar
 
[BDD] Introduction to Behat (PL)
Piotr Pelczar
 
How NOT to write in Node.js
Piotr Pelczar
 
Liquibase - database structure versioning
Piotr Pelczar
 
Scalable Web Apps
Piotr Pelczar
 

Recently uploaded (20)

PDF
REPORT: Heating appliances market in Poland 2024
SPIUG
 
PDF
NewMind AI Weekly Chronicles - July'25 - Week IV
NewMind AI
 
PDF
A Day in the Life of Location Data - Turning Where into How.pdf
Precisely
 
PDF
Chapter 2 Digital Image Fundamentals.pdf
Getnet Tigabie Askale -(GM)
 
PPT
L2 Rules of Netiquette in Empowerment technology
Archibal2
 
PDF
Orbitly Pitch Deck|A Mission-Driven Platform for Side Project Collaboration (...
zz41354899
 
PPTX
What-is-the-World-Wide-Web -- Introduction
tonifi9488
 
PDF
Unlocking the Future- AI Agents Meet Oracle Database 23ai - AIOUG Yatra 2025.pdf
Sandesh Rao
 
PDF
Building High-Performance Oracle Teams: Strategic Staffing for Database Manag...
SMACT Works
 
PDF
How Open Source Changed My Career by abdelrahman ismail
a0m0rajab1
 
PDF
SparkLabs Primer on Artificial Intelligence 2025
SparkLabs Group
 
PDF
Using Anchore and DefectDojo to Stand Up Your DevSecOps Function
Anchore
 
PPTX
New ThousandEyes Product Innovations: Cisco Live June 2025
ThousandEyes
 
PDF
Structs to JSON: How Go Powers REST APIs
Emily Achieng
 
PDF
Best ERP System for Manufacturing in India | Elite Mindz
Elite Mindz
 
PPTX
Stamford - Community User Group Leaders_ Agentblazer Status, AI Sustainabilit...
Amol Dixit
 
PDF
Revolutionize Operations with Intelligent IoT Monitoring and Control
Rejig Digital
 
PPTX
OA presentation.pptx OA presentation.pptx
pateldhruv002338
 
PDF
Cloud-Migration-Best-Practices-A-Practical-Guide-to-AWS-Azure-and-Google-Clou...
Artjoker Software Development Company
 
PDF
Automating ArcGIS Content Discovery with FME: A Real World Use Case
Safe Software
 
REPORT: Heating appliances market in Poland 2024
SPIUG
 
NewMind AI Weekly Chronicles - July'25 - Week IV
NewMind AI
 
A Day in the Life of Location Data - Turning Where into How.pdf
Precisely
 
Chapter 2 Digital Image Fundamentals.pdf
Getnet Tigabie Askale -(GM)
 
L2 Rules of Netiquette in Empowerment technology
Archibal2
 
Orbitly Pitch Deck|A Mission-Driven Platform for Side Project Collaboration (...
zz41354899
 
What-is-the-World-Wide-Web -- Introduction
tonifi9488
 
Unlocking the Future- AI Agents Meet Oracle Database 23ai - AIOUG Yatra 2025.pdf
Sandesh Rao
 
Building High-Performance Oracle Teams: Strategic Staffing for Database Manag...
SMACT Works
 
How Open Source Changed My Career by abdelrahman ismail
a0m0rajab1
 
SparkLabs Primer on Artificial Intelligence 2025
SparkLabs Group
 
Using Anchore and DefectDojo to Stand Up Your DevSecOps Function
Anchore
 
New ThousandEyes Product Innovations: Cisco Live June 2025
ThousandEyes
 
Structs to JSON: How Go Powers REST APIs
Emily Achieng
 
Best ERP System for Manufacturing in India | Elite Mindz
Elite Mindz
 
Stamford - Community User Group Leaders_ Agentblazer Status, AI Sustainabilit...
Amol Dixit
 
Revolutionize Operations with Intelligent IoT Monitoring and Control
Rejig Digital
 
OA presentation.pptx OA presentation.pptx
pateldhruv002338
 
Cloud-Migration-Best-Practices-A-Practical-Guide-to-AWS-Azure-and-Google-Clou...
Artjoker Software Development Company
 
Automating ArcGIS Content Discovery with FME: A Real World Use Case
Safe Software
 

Asynchronous programming done right - Node.js

  • 1. Asynchronous programming done right. Without race conditions ..ions ..io on ..ns ditions. by Piotr Pelczar (Athlan)
  • 3. About me Piotr Pelczar Freelancer for 8yrs PHP, Node.js, Java/Groovy Zend Certified Engineer IPIJ, Startups
  • 4. Stay in touch athlan.pl [email protected] facebook.com/piotr.pelczar github.com/athlan slideshare.net/piotrpelczar linkedin.com/in/ppelczar
  • 5. Asynchronous programming Asynchronous actions are actions executed in a non-blocking scheme, allowing the main program flow to continue processing.
  • 6. How software lives in hardware? Operating systems are process based Each process has assigned processor, registers, memory
  • 7. How software lives in hardware? Process paralelism using threads (thread pools) Switching processor over processes/threads causes context switching
  • 8. 1. context switching = wasting time
  • 9. Sync programming In trivial, sequential approach Each operation is executed sequentially: O(t) > O(t+1) if O(t) stucks, O(t+1) waits...
  • 11. This is cool, software flow is predictible But not in high throughput I/O I/O costs because of waiting time...
  • 12. High throughput I/O High throughput I/O doesn't mean: Memory operations Fast single-thread computing
  • 13. High throughput I/O High throughput I/O means: HTTP requests Database connections Queue system dispatching HDD operations
  • 14. 2. Avoid I/O blocking
  • 15. 2. Avoid I/O blocking
  • 16. Single-threaded, event loop model Imagine a man, who has a task: Walk around When bucket is full of water, just pour another bucket Go to next bucket
  • 17. There is no sequences In async programming, results appears in no sequences operation1(); // will output "operation1 finished." operation2(); // will output "operation2 finished." operation3(); // will output "operation3 finished."
  • 18. There is no sequences operation1() would be var amqp = require("amqp") var eventbus = amqp.createConnection(); console.log("AMQP connecting..."); eventbus.on("ready", function() { console.log("AMQP connected..."); callback(); return; });
  • 19. There is no sequences operation2() would be var redis = require("redis") var conn = redis.createClient(port, host, options); console.log("Redis connecting..."); conn.auth(pass, function(err) { if(err) console.log("Redis failed..."); else console.log("Redis connected..."); callback(); return; });
  • 20. There is no sequences operation3() would be var mongojs = require("mongojs"); console.log("Mongo connecting..."); var conn = mongojs.connect(connectionString); // blocking operation console.log("Mongo connected..."); callback(); return;
  • 21. There is no sequences Expectations? AMQP connecting... // operation1() AMQP connected... // operation1() Redis connecting... // operation2() Redis failed... // operation2() Mongo connecting... // operation3(), blocking Mongo connected... // operation3()
  • 22. There is no sequences Expectations?
  • 23. There is no sequences The result: AMQP connecting... // operation1() Redis connecting... // operation2() Mongo connecting... // operation3(), blocking Mongo connected... // operation3() Redis failed... // operation2() AMQP connected... // operation1()
  • 24. There is no sequences
  • 25. So... what functions returns? You can perform future tasks in function, so what will be returned? value123 will be returned, function my_function() { operation1(); operation2(); operation3(); return "value123"; } just after blocking code, without waiting for non-blocking.
  • 26. Assume: Functions does NOT returns values The function block is executed immedietally from top to bottom. You cannot rely to return value, because it is useless.
  • 27. Callbacks Callback is the reference to function. var callbackFunction = function(result) { console.log("Result: %s", result) } When operation is done, the callback function is executed. callbackFunction("test1") // "Result: test1" will be printed out
  • 28. Callbacks If callbackFunction is a variable (value = reference), so can be passed it via function argument. var callbackFunction = function() { ... } someOtherFunction(callbackFunction); function someOtherFunction(callback) { callback(); // execute function from argument }
  • 29. Callbacks Functions can be defined as anonymous (closures) function someOtherFunction(callback) { var arg1 = "test"; callback(arg1); // execute function from argument } someOtherFunction(function(arg1) { console.log('done... %s', arg1); })
  • 30. Callbacks can be nested Nesting callbacks makes code unreadeable: var amqp = require('amqp'); var connection = amqp.createConnection(); connection.on('ready', function() { connection.exchange("ex1", function(exchange) { connection.queue('queue1', function(q) { q.bind(exchange, 'r1'); q.subscribe(function(json, headers, info, m) { console.log("msg: " + JSON.stringify(json)); }); }); }); });
  • 31. Callbacks can be nested Nesting callbacks makes code unreadeable: var amqp = require('amqp'); var connection = amqp.createConnection(); connection.on('ready', function() { connection.exchange("ex1", function(exchange) { connection.queue('queue1', function(q) { q.bind(exchange, 'r1'); q.subscribe(function(json, headers, info, m) { console.log("msg: " + JSON.stringify(json)); table.update(select, data, function() { table.find(select, function(err, rows) { // inserted rows... } }); }); }); }); });
  • 32. Asynchronous control flows Promise design pattern Libraries that manages callbacks references
  • 33. Promise design pattern 1. Client fires function that will return result in the future in the future, so it is a promise 2. Function returns promise object immedietaly before non-blocking operations 3. Client registers callbacks 4. Callbacks will be fired in the future, when task is done var resultPromise = loader.loadData(sourceFile) resultPromise(function success(data) { // this function will be called while operation will succeed }, function error(err) { // on fail })
  • 34. Promise design pattern 1. Create deferred object 2. Return def.promise 3. Call resolve() or reject() var loadData = function(sourceFile) { var def = deferred() , proc = process.spawn('java', ['-jar', 'loadData.jar', sourceFile]) var commandProcessBuff = null , commandProcessBuffError = null; proc.stdout.on('data', function (data) { commandProcessBuff += data }) proc.stderr.on('data', function (data) { commandProcessBuffError += data }) proc.on('close', function (code) { if(null !== commandProcessBuffError) def.reject(commandProcessBuffError) else def.resolve(commandProcessBuff) }) return def.promise }
  • 36. Async Node.js library Provides control flows like: Sequences (series) Waterfalls (sequences with parameters passing) Parallel (with limit) Some/every conditions While/until Queue
  • 38. Async Node.js library Series async.series([ function(callback) { // operation1 }, function(callback) { // operation2 }, function(callback) { // operation3 } ], function() { console.log('all operations done') })
  • 39. Async Node.js library Parallel async.parallel([ function(callback) { // operation1 }, function(callback) { // operation2 }, function(callback) { // operation3 } ], function() { console.log('all operations done') })
  • 40. Async Node.js library Parallel limit
  • 41. Async Node.js library Parallel limit var tasks = [ function(callback) { // operation1 }, function(callback) { // operation2 }, // ... ] async.parallelLimit(tasks, 2, function() { console.log('all operations done') })
  • 42. Async Node.js library Waterfall async.waterfall([ function(callback) { // operation1 callback(null, arg1, arg2) }, function(arg1, arg2, callback) { // operation2 callback(null, foo, bar) }, function(foo, bar, callback) { // operation3 } ], function() { console.log('all operations done') })
  • 43. Async Node.js library Whilst async.doWhilst( function(done) { // operation1 done(null, arg1, arg2) }, function() { return pages < limit } ], function() { console.log('done') })
  • 44. Asynchronous programming traps Dealing with callbacks may be tricky. Keep your code clean.
  • 45. Unnamed callbacks Keep your code clean, don't name callback function callback function doSomething(callback) { return callback; }
  • 46. Unnamed callbacks function doSomething(callback) { doAnotherThing(function(callback2) { doYetAnotherThing(function(callback3) { return callback(); }) }) }
  • 47. Unnamed callbacks Instead of this, name your callbacks function doSomething(done) { doAnotherThing(function(doneFetchingFromApi) { doYetAnotherThing(function(doneWritingToDatabase) { return done(); }) }) }
  • 48. Double callbacks function doSomething(done) { doAnotherThing(function (err) { if (err) done(err); done(null, result); }); } Callback is fired twice!
  • 49. Double callbacks Fix: Always prepend callback execution with return statement. function doSomething(done) { doAnotherThing(function (err) { if (err) return done(err); return done(null, result); }); } Normally, return ends function execution, why do not keep this rule while async.
  • 50. Double callbacks Double callbacks are very hard to debug. The callback wrapper can be written and execute it only once. setTimeout(function() { done('a') }, 200) setTimeout(function() { done('b') }, 500)
  • 51. Double callbacks var CallbackOnce = function(callback) { this.isFired = false this.callback = callback } CallbackOnce.prototype.create = function() { var delegate = this return function() { if(delegate.isFired) return delegate.isFired = true delegate.callback.apply(null, arguments) } }
  • 52. Double callbacks obj1 = new CallbackOnce(done) // decorate callback safeDone = obj1.create() // safeDone() is proxy function that passes arguments setTimeout(function() { safeDone('a') // safe now... }, 200) setTimeout(function() { safeDone('b') // safe now... }, 500)
  • 53. Unexpected callbacks Never fire callback until task is done. function doSomething(done) { doAnotherThing(function () { if (condition) { var result = null // prepare result... return done(result); } return done(null); }); } The ending return will be fired even if condition pass.
  • 54. Unexpected callbacks Never fire callback until task is done. function doSomething(done) { doAnotherThing(function () { if (condition) { var result = null // prepare result... return done(result); } else { return done(null); } }); }
  • 55. Unexpected callbacks Never use callback in try clause! function (callback) { another_function(function (err, some_data) { if (err) return callback(err); try { callback(null, JSON.parse(some_data)); // error here } catch(err) { callback(new Error(some_data + ' is not a valid JSON')); } }); } If callback throws an exception, then it is executed exactly twice!
  • 56. Unexpected callbacks Never use callback in try clause! function (callback) { another_function(function (err, some_data) { if (err) return callback(err); try { var parsed = JSON.parse(some_data) } catch(err) { return callback(new Error(some_data + ' is not a valid JSON')); } callback(null, parsed); }); }
  • 57. Unexpected callbacks Never use callback in try clause!
  • 58. Take care of events Read docs carefully. Really. function doSomething(done) { var proc = process.spawn('java', ['-jar', 'loadData.jar', sourceFile]) var procBuff = ''; proc.stdout.on('data', function (data) { procBuff += data; }); // WAT?! proc.stderr.on('data', function (data) { done(new Error("An error occured: " + data)) }); proc.on('close', function (code) { done(null, procBuff); } }
  • 59. Take care of events Read docs carefully. Really. function doSomething(done) { var proc = process.spawn('java', ['-jar', 'loadData.jar', sourceFile]) var procBuff = ''; var procBuffError = ''; proc.stdout.on('data', function (data) { procBuff += data; }); proc.stderr.on('data', function (data) { proc += data; }); proc.on('close', function (code) { if(code !== 0) { return done(new Error("An error occured: " + procBuffError)); } else { return done(null, procBuff) } } }
  • 60. Unreadable and logs Keep in mind, that asynchronous logs will interweave There are not sequenced Or there will be same log strings
  • 61. Unexpected callbacks Asynchronous logs will interweave
  • 62. Unreadable and logs Logs without use context are useless... function getResults(keyword, done) { http.request(url, function(response) { console.log('Fetching from API') response.on('error', function(err) { console.log('API error') }) }); }
  • 63. Unreadable and logs function getResults(keyword, done) { var logContext = { keyword: keyword } http.request(url, function(response) { console.log(logContext, 'Fetching from API') response.on('error', function(err) { console.log(logContext, 'API error') }) }); }
  • 64. Unreadable and logs Centralize your logs - use logstash And make them searcheable - Elasticsearch + Kibana
  • 65. Too many opened background-tasks While running parallel in order to satisfy first-better algorithm, others should be aborted
  • 66. Too many opened background-tasks Provide cancellation API: var events = require('events') function getResults(keyword) { var def = deferred() var eventbus = new events.EventEmitter() var req = http.request(url, function(response) { var err = null , content = null res.on('data', function(chunk) { content += chunk; }); response.on('close', function() { if(err) return def.reject(err) else return def.resolve(content) }) response.on('error', function(err) { err += err }) });
  • 67. Too many opened background-tasks Provide cancellation API: var response = getResults('test') response.result(function success() { // ... }, function error() { // ... }) // if we need response.events.emit('abort')
  • 68. Everything runs in parallel except your code. When currently code is running, (not waiting for I/O descriptors) whole event loop is blocked.
  • 69. THE END by Piotr Pelczar
  • 70. Q&A by Piotr Pelczar