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.