meets
callbacks
What we will See
- Continuations
- Practical session: objects
- Callbacks
- Practical session: removing callbacks
Continuations
Continuation-Passing Style
Continuations
Functional Programming Style
CPS: Continuation-passing Style
Also known as: callbacks
State is passed as parameters and clausures
Example: Socket server
var net = require('net');
var port = 1702;
var server = net.createServer(function(connection) {
console.log('Connection to %s open', port);
connection.write('Hello?\r\n');
connection.on('data', function(data) {
if (String(data).trim() != 'hello) {
connection.write('ERROR\r\n');
} else {
connection.end('world\r\n');
console.log('Connection to %s closed', port);
}
});
});
server.listen(port);
Continuations in yellowParameters in bold
Clausures in cyan
Another View of the Same
var net = require('net');
var port = 1702;
var server = net.createServer(function(connection) {
console.log('Connection open');
connection.write('Hello?\r\n');
connection.on('data', function(data) {
if (String(data).trim() != 'hello') {
connection.write('ERROR\r\n');
} else {
connection.end('world\r\n');
console.log('connection closed');
}
});
});
server.listen(port);
Three different levels of execution
ASYNC
Library for async execution
Based on continuations
-
async.series()
: runs functions one after the other
-
async.parallel()
: runs everything at the same time
-
async.waterfall()
: passes results from one to the next
Fuente: async
Async.series()
Example:
// an example using an object instead of an array async.series({ one: function(callback){ setTimeout(function(){ callback(null, 1); }, 200); }, two: function(callback){ setTimeout(function(){ callback(null, 2); }, 100); } }, function(err, results) { console.log('Results: %j', results); });Source: async
Practical session 1: async
Use the async module to read a number of values
and add them up
Careful with clausures!
Tech Spec
Read all the files:
- http://stats.mediasmart.es/bulk/test-2014/account-01.json
- ...
- http://stats.mediasmart.es/bulk/test-2014/account-05.json
For each one parse the JSON file,
read the "Debt" field,
and aggregate all values
Sample
Read a JSON:
var request = require('request'); var url = 'http://stats.mediasmart.es/bulk/test-2014/account-01.json'; request(file, function(err,res,body) { if (!err && res.statusCode==200) { body = JSON.parse(body); console.log('Debt: %s', body.Debt); } });
Now do that 5 times
Second level function
Function that returns a function (which reads JSON):
var request = require('request'); function getDebtReader(url) { return function(callback) { request(file, function(error, result, body) { if (error || result.statusCode != 200) { return callback('Could not read ' + url); } body = JSON.parse(body); return callback(null, body.Debt); }); }; }
Good job!
Callbacks
Introduction to "Callback Hell"
simplecached test
'use strict'; var client = require('./lib/client.js'); var options = { port: 11311, host: 'localhost' }; var client = new client.Client(options, function(error) { console.assert(!error, 'Could not open connection'); var key = 'testing'; var value = 'real value'; client.set(key, value, function(error, result) { console.assert(!error, 'Error setting key'); console.assert(result, 'Could not set key'); client.get(key, function(error, result) { console.assert(!error, 'Error getting key'); console.assert(result == value, 'Invalid get key'); client.delete(key, function(error, result) { console.assert(!error, 'Error deleting key'); console.assert(result, 'Could not delete key'); client.close(function(error) { console.assert(!error, 'Error closing client'); }); }); }); }); });
Source: simplecached
Callback Hell
The fearsome callback pyramid
Infinite nested continuations
Abusing your lambdas (anonymous functions)
Hard to follow, debug and refactor
Simple Solutions
Use named functions
Create an object with named attributes
Clausures become attributes
Use async: async.waterfall()
Use events: EventEmitter
Advanced Solutions
Practical Session 2: Removing callbacks
Review the callback pyramid
Original code: socket server
Transform into an object with attributes
Not more than two nested callbacks
socket server
var net = require('net');
var port = 1702;
var server = net.createServer(function(connection) {
console.log('Connection to %s open', port);
connection.write('Hello?\r\n');
connection.on('data', function(data) {
if (String(data).trim() != 'hello) {
connection.write('ERROR\r\n');
} else {
connection.end('world\r\n');
console.log('Connection to %s closed', port);
}
});
});
server.listen(port);
Continuations in yellowParameters in bold
Clausures in cyan
Success!
Thanks!
IronHack meets Node.js: Callbacks
By Alex Fernández
IronHack meets Node.js: Callbacks
IronHack webdev bootcamp Aug 2015: continuations and callbacks.
- 2,375