Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Javascript Promises/Q Library

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

  • Login to see the comments

Javascript Promises/Q Library

  1. 1. Javascript Promises/Q library Jonathan Altman node.dc March 2013 @async_io http://async.io/
  2. 2. What is a Promise?The simplest explanation: it is an easy way to avoid writing the Pyramid of Doom
  3. 3. 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
  4. 4. 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
  5. 5. 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
  6. 6. Is That Not Good Enough?var later = Q.nfcall(nodedc.wait_a_few_slides); // or: we’ll come back to it
  7. 7. Promises: Longer Explanation“A Promise is an object representation of an event. In the course of itslife, a Promise goes from a pending state, when it’s called, to a resolved orrejected state, when it’s been completed, or it could also stay pendingforever and is never resolved.” http://flaviocopes.com/deferred-and-promises-in-javascript/
  8. 8. 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
  9. 9. Promises provide a solid abstraction for representing the state of an asynchronous call and writing flow ofcontrol code based on that state
  10. 10. 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
  11. 11. 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
  12. 12. 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
  13. 13. later.then(function(){Provides separation of concerns between wrapping and flow of control handling of deferred activities // that separation is the key });
  14. 14. Promises can (mostly) be shared across libraries
  15. 15. 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
  16. 16. 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
  17. 17. Generating Promises With Q
  18. 18. Q.fcall/nfcall: Wrap an Async method with a Promisefunction 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)
  19. 19. Q.defer: Interject Promise Support• Use when you have to intermingle other logic inside callback workfunction 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; };
  20. 20. 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 () {});
  21. 21. Control Flow and Error Handling
  22. 22. Simple Flow• Use then/fail (and .done() to avoid swallowing unhandled exceptions)• You can chain then callsQ.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
  23. 23. 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
  24. 24. Testing
  25. 25. 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
  26. 26. Mocha + Chai + Chai-as-Promised• Adds testability methods to promises supporting BDD• Note the use of done, which signals the async part of mochait(Should error on short barcode format, function(done){ var promise = lookupBarcode(lookupData.shortGtinData.gtin); promise.should.be.rejected.and.notify(done);});
  27. 27. Resources• Q javascript library: https://github.com/kriskowal/q• Q documentation: http://documentup.com/kriskowal/q/
  28. 28. Thank you. Questions?

×