"Function to be called when async operation is complete"
//without CSP
function self (x) { return x; }
function addOne(x) { return 1 + x; }
function double(x) { return 2 * x; }
//without CSP
var startVal = 2;
var selfed = self(startVal);
var oneAdded = addone(selfed);
var doubled = double(oneAdded);
console.log(doubled); // output: 6
//WITH CSP
function self (x, cb) { cb(x); }
function addOne(x, cb) { cb(1 + x); }
function double(x, cb) { cb(2 * x); }
//WITH CSP
var startVal = 2;
self(startVal, function (selfed){
//do stuff with selfed
});
double(starVal, function(doubled){
//do stuff with doubled value
});
//WITH CSP
function self (x, cb) { cb(x); }
function addOne(x, cb) { cb(1 + x); }
function double(x, cb) { cb(2 * x); }
var startVal = 2;
self(startVal, function (selfed){
addOne(selfed, function (oneAdded){
double(oneAdded, function (doubled){
console.log(doubled); //outputs 6
});
});
});
Yikes!
try{
var results = readFile('myFile');
}catch(e){
console.error('bad things :(');
}
console.log(results);
//do other stuff later...
Blocking!
readFile('myFile', function(err, results){
if(err){ return console.error('bad things :(');
console.log(results);
});
//do other stuff right away!
fs.readfile
//filename: async-flow-control/start/read-file.js
var fs = require('fs');
var filename = 'letter.txt';
fs.readFile(filename, callback);
function callback(err, data){
//if err, console.error(err)
//else console.log file contents
}
Hints:
data
is a Buffer
. It has a .toString
methodletter.txt
is relative to CWDasyncOperation(/*...*/, function(error, /*...*/);
Up Next: Callback Hell
users.json
fs.readFile('users.json', 'utf-8', function (err, contents){
if(err){ throw err; }
var users = JSON.parse(contents);
users.forEach(function(user){
db.accounts.findOne({id: user.id}, function(err, address){
if(err){ throw err; }
var filename = 'address' + address.id + '.json';
fs.writeFile(filename, 'utf-8', address, function(err){
if(err){ throw err; }
console.log(filename + ' written successfully!');
});
});
});
});
fs.readFile('users.json', 'utf-8', function processUsers(err, contents){
if(err){ throw err; }
var users = JSON.parse(contents);
users.forEach(function lookupAddress(user){
db.accounts.findOne({id: user.id}, function writeAddress(err, address){
if(err){ throw err; }
var filename = 'address' + address.id + '.json';
fs.writeFile(filename, 'utf-8', address, function outputResults(err){
if(err){ throw err; }
console.log(filename + ' written successfully!');
});
});
});
});
fs.readFile('users.json', 'utf-8', processUsers);
function processUsers(err, contents){
if(err){ throw err; }
var users = JSON.parse(contents);
users.forEach(lookupAddress);
});
function lookupAddress(user){
db.accounts.findOne({id: user.id}, writeAddress);
}
function writeAddress(err, address){
if(err){ throw err; }
var filename = 'address' + address.id + '.json';
fs.writeFile(filename, 'utf-8', address, outputResults);
}
function outputResults(err){
if(err){ throw err; }
console.log(filename + ' written successfully!');
}
Clean up the following callback heck:
//async-flow-control/start/callback-heck.js
function self (x, cb) { cb(null, x); }
function addOne(x, cb) { cb(null, 1 + x); }
function double(x, cb) { cb(null, 2 * x); }
var startVal = 2;
self(startVal, function (err, selfed){
addOne(selfed, function (err, oneAdded){
double(oneAdded, function (err, doubled){
console.log(doubled); //outputs 6
});
});
});
Hints:
Up Next: EventEmitter
s
EventEmitter
on(event, handlerFunction)
emit(event, data)
//async-flow-control/event-emitter-example.js
var EventEmitter = require('events');
var ee = new EventEmitter();
ee.on('message', function logMessage(msg){
console.log('new message: ' + msg.text);
});
ee.emit({ text : 'hello!', sender: 'sequoia'});
ee.emit({ text : 'world!', sender: 'sequoia'});
var messages = [];
ee.on('message', function collectMessage(msg){
messages.push(msg);
});
start/event-emitter.js
increment
each time counter is incrementedcounter
value as event datacounter
valueHints:
emitter.emit(name, data)
emitter.on(name, function(data){})
Extra Credit:
done
eventdone
to log "DONE" then process.exit()
Up Next: Promises
db.getRecords()
.then(formatRecords)
.then(sendToUser);
What is a promise?
.then
methodonFulfilled
functiononRejected
functionreadFilePromise('users.json')
.then(
function success(results){
console.log(results);
},
function failure(err){
console.error(err);
}
);
var promise = readFilePromise('users.json');
promise
.then(filterUsers, handleError)
.then(formatRecords, handleError)
.then(writeFile, handleError);
function getUser(id){
return restPromiseAPI.getOne({
type : 'user',
id : id
});
}
var userPromise = getUser(id);
userPromise.then(updateUI, logError);
function readFilePromise(filename){
return new Promise(function(resolve, reject){
fs.readFile(filename, 'utf-8', function(err, contents){
if(err) return reject(err);
resolve(contents);
});
}
"Promisify" readFile
. This should work:
//filename: async/read-file-promise.js
function print(text){ /*...*/ }
function handleError(err){ /*...*/ }
readFile('letter.txt')
.then(print, handleError);
Hints:
function returnsPromise(){
return new Promise(function(resolve, reject){
// do something...
// reject(err); //or
// resolve(results);
});
}
catch
methodmap
, filter
, etc.)promisify
& promisifyAll
Promise = require('bluebird');
var fs = Promise.promisifyAll(require(fs));
fs.readFileAsync('myfile.txt', 'utf-8')
.then(print)
.catch(handleError);
Promise = require('bluebird');
var fs = Promise.promisifyAll(require(fs));
fs.readFileAsync('users.json', 'utf-8')
.then(JSON.parse)
.filter(justAdmins)
.tap(function log(admins){
console.log(admins);
})
.map(sendNotification)
.then(doTheNextThing)
.catch(handleError);
function justAdmins(user){
return user.role == 'admin';
}
Up Next: The Event Loop