Top Banner
Javascript Promises/Q library Jonathan Altman node.dc March 2013 @async_io http://async.io/
28

Javascript Promises/Q Library

May 06, 2015

Download

Technology

async_io

Presentation I gave to the node.dc meetup group March 13, 2013 on using Promises and the Q library to make flow of control easier to reason about in Javascript code using async and callbacks
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Javascript Promises/Q Library

Javascript Promises/Q libraryJonathan Altman

node.dc March 2013@async_io

http://async.io/

Page 2: Javascript Promises/Q Library

What is a Promise? The simplest explanation: it is an easy way to avoid writing the Pyramid of Doom

Page 3: Javascript Promises/Q Library

Pyramid of Doomstep1(function (value1) {

step2(value1, function(value2) {

step3(value2, function(value3) {

step4(value3, function(value4) {

// Do something with value4

});

});

});

}); // from https://github.com/kriskowal/q

Page 4: Javascript Promises/Q Library

Why Promises? What about?

• async: http://github.com/caolan/async

• step: https://github.com/creationix/step

• flow-js: https://github.com/willconant/flow-js

• ...you get the point

Page 5: Javascript Promises/Q Library

Non-Promises Fix:async.series({

normalize: function(callback){// Bodies removed for brevity

}, compose: function(callback){}, invert: function(callback){}// A bunch more stuff killed

}, function (err, results){if (!err ) {err = new Error('Results did not contain a valid image buffer')

}else {callback(err, results.imageBuffer);

}}

}); //https://github.com/jonathana/heatNode/blob/master/lib/imageGen/generateimages.js

Page 6: Javascript Promises/Q Library

Is That Not Good Enough?var later = Q.nfcall(nodedc.wait_a_few_slides);

// or: we’ll come back to it

Page 7: Javascript Promises/Q Library

Promises: Longer Explanation“A Promise is an object representation of an event. In the course of its life, a Promise goes from a pending state, when it’s called, to a resolved or rejected state, when it’s been completed, or it could also stay pending forever and is never resolved.”

http://flaviocopes.com/deferred-and-promises-in-javascript/

Page 8: Javascript Promises/Q Library

Say What?

• Promises take a call to an asynchronous function and wrap it with an object whose methods proxy when the wrapped function either completes or errors

• A good Promise library also provides a set of control methods on that object wrapper to handle composition of multiple Promise-ified asynchronous method calls

• Promises use the best qualities of an object--encapsulation of state--to track the state of an asynchronous call

Page 9: Javascript Promises/Q Library

Promises provide asolid abstractionfor representing the

state of an asynchronous calland writing flow of

control code based on that state

Page 10: Javascript Promises/Q Library

Pyramid of Doom Againstep1(function (value1) {

step2(value1, function(value2) {

step3(value2, function(value3) {

step4(value3, function(value4) {

// Do something with value4

});

});

});

}); // from https://github.com/kriskowal/q

Page 11: Javascript Promises/Q Library

Pyramid of Doom on PromisesQ.fcall(step1) // This returns a Promise obj.then(step2).then(step3).then(step4).then(function (value4) { // Do something with value4}, function (error) { // Handle any error from step1 through step4}).done(); // from https://github.com/kriskowal/q

Page 12: Javascript Promises/Q Library

Again, Why Promises?

• It’s a spec: http://wiki.commonjs.org/wiki/Promises/A

• Generally supported by a bunch of libs both browser and server-side:

• jQuery (sort of, supposedly doesn’t fully work like Promises/A)

• AngularJS

• Q library (https://github.com/kriskowal/q)

• Provides separation of concerns between wrapping and flow of control handling of deferred activities

Page 13: Javascript Promises/Q Library

later.then(function(){Provides separation of concerns between wrapping and flow of

control handling of deferred activities

// that separation is the key

});

Page 14: Javascript Promises/Q Library

Promises can (mostly) be shared across libraries

Page 15: Javascript Promises/Q Library

Sharing

• Many libraries can exchange Promise objects

• AngularJS’ Promise API is explicitly based off a subset of Q. If Q is loads first, AngularJS just uses that

• jQuery’s promises can be consumed by Q, with some adaptations

Page 16: Javascript Promises/Q Library

So Why Q?

• Q consumes Promises from most other libraries

• Pure Javascript library

• Can be used both client-side (browser or e.g. Phonegap) and server-side (npm install q, but you’re using package.json, right?)

• Provides utilities to make it easy to write Promise-based code or wrap non-Promise-based functions

• Provides a library of methods to build control flow around Promise results and errors

• Small (enough?): ~1400 SLOC, ~ 8.5kb minified

Page 17: Javascript Promises/Q Library

Generating Promises With Q

Page 18: Javascript Promises/Q Library

Q.fcall/nfcall: Wrap an Async method with a Promise

function writeError(errMessage) { return Q.nfcall(fs.writeFile, "errors.log", errMessage);}• nfcall: node function call. Sort of a misnomer, original intent was to

make it easy to wrap node library/module calls into Promises, but works for any async call

• fcall: turns functions synchronously returning a value into a Promise, • You can make it so it’s Promises all the way down (at least until you hit

the turtles)

Page 19: Javascript Promises/Q Library

Q.defer: Interject Promise Support• Use when you have to intermingle other logic inside callback work

function getLocation() { var deferred = Q.defer(); console.log("Calling getCurrentPosition"); navigator.geolocation.getCurrentPosition(function(position) { deferred.resolve(position); console.log("getCurrentPosition resolved"); }, function(error){ deferred.reject(error); console.log("getCurrentPosition errored"); }); return deferred.promise; };

Page 20: Javascript Promises/Q Library

Q.when: Wrapping Other Libraries’ Promises

• From the Q documentation: “Not all promise libraries make the same guarantees as Q and certainly don’t provide all of the same methods. Most libraries only provide a partially functional then method.”

return Q.when($.ajax(...)).then(function () {});

Page 21: Javascript Promises/Q Library

Control Flow and Error Handling

Page 22: Javascript Promises/Q Library

Simple Flow• Use then/fail (and .done() to avoid swallowing unhandled exceptions)

• You can chain then calls

Q.fcall(step1) // This returns a Promise obj.then(step2).then(step3).then(step4).then(function (value4) { // Do something with value4}, function (error) { // Handle any error from step1 through step4}).done(); // from https://github.com/kriskowal/q

Page 23: Javascript Promises/Q Library

More Complex Handling

• Q.reduce(): Chain indeterminate-length sequential chains

• all(): Turn multiple Promises in an array into a single Promise. Fails at the first failure from any Promise, returning that failure

• allResolved(): Turn multiple Promises in an array into a single Promise. Succeeds when all Promises complete, resolved or failed, and resolves with the array of Promises

Page 24: Javascript Promises/Q Library

Testing

Page 25: Javascript Promises/Q Library

Mocha + Chai + Chai-as-Promised

• Mocha: http://visionmedia.github.com/mocha/ -- unit testing framework

• Chai: http://chaijs.com/ -- BDD add-on for Mocha

• Chai-as-promised: https://github.com/domenic/chai-as-promised -- Promises-enables Chai/Mocha

Page 26: Javascript Promises/Q Library

Mocha + Chai + Chai-as-Promised

• Adds testability methods to promises supporting BDD

• Note the use of done, which signals the async part of mocha

it('Should error on short barcode format', function(done){ var promise = lookupBarcode(lookupData.shortGtinData.gtin); promise.should.be.rejected.and.notify(done);});

Page 27: Javascript Promises/Q Library

Resources

• Q javascript library: https://github.com/kriskowal/q

• Q documentation: http://documentup.com/kriskowal/q/

Page 28: Javascript Promises/Q Library

Thank you. Questions?