On Github masotime / promises-presentation
by Benjamin Goh, made using reveal.js
Benjamin Goh
You write from A-Z, and expect execution from A-Z
console.log('Hello');
while(true);
console.log('world'); // this will never be reached
Events versus threads - onclick, onmouseover
document.getElementById('mybutton').onclick = function(e) {
alert('hello world');
};
Pass a function as an argument
function nonBlocking(arg, callback) {
setTimeout(function() { // "spawn thread"
try {
var data = readFile(arg); // blocking code
callback(null, data); // event fired, data returned
} catch(e) {
callback(e); // event fired, error occurred
}
}, 100);
}
console.log('Hello');
nonBlocking('pineapple.txt', function(result) {
console.log(result);
}); // this doesn't block
console.log('World');
function async(...args, callback) { // LAST ARG MUST BE CALLBACK
// synchronous code
if (success) {
callback(null, result);
} else {
callback(err, result); // if any
}
}
function callback(error, result) { // FIRST ARG MUST BE ERROR
if (error) {
// handle error
} else {
// so something with the result
}
}
Map each array element through a function, return a new array
var numbers = [1,2,3,4,5];
var inc = function(x) { return x+1 };
var newNumbers = numbers.map(inc); // newNumbers = [2,3,4,5,6]
Go through each array element, reduce it to a single result
var adder = function(sum, current) { return sum + current };
var sum = numbers.reduce(adder); // sum = 1 + 2 + 3 + 4 + 5 = 15
var files = ['data/data1', 'data/data2', 'data/data3'],
filestats;
try {
filestats = files.map(fs.stat);
useFileStats(filestats);
} catch (e) {
console.error(e);
}
useThirdFileSize(filestats[2].size);
They represent a “future value” which I can’t give right away because I need to work on it.
Callbacks don’t give you anything, you’ll just have to wait for them to call back before you can do something.
function doPerformanceReview() {
var deferred = Q.defer();
setTimeout(function() {
deferred.resolve('My review');
}, 2000);
return deferred.promise; // RETURNS A PROMISE
}
function doPerformanceReview(callback) {
setTimeout(function() {
callback(null, 'My review');
}, 2000); // RETURNS NOTHING
}
Promises in Javascript usually implement what is known as the Promises/A+ standard
Q is the most popular framework, but there are many others, like Bluebird, rsvp, etc.
var statPromises = files.map(function(file) { return fs_stat(file); }); // array of promises
Q.all(statPromises).then(useFileStats)
.done(undefined, function(err) {
console.error('problem trying to stat all files', err); // localized error handling
});
statPromises[2].get('stat')
.then(useThirdFileSize).done();
var files = ['data/data1', 'data/data2', 'data/data3'],
try {
useFileStats(files.map(fs.stat));
} catch (e) {
console.error(e);
}
useThirdFileSize(fs.stat(files[2]).size);
async is good for flow control, but it doesn’t help you think in terms of dependencies.
Let's try to model a real world example using Q.
My recommendation? Use it when you have data from multiple sources that must be combined in different ways.