Javascript Promises/Q Library

  • 13,505 views
Uploaded on

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

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

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
13,505
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
97
Comments
2
Likes
20

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Javascript Promises/Q library Jonathan Altman node.dc March 2013 @async_io http://async.io/
  • 2. What is a Promise?The simplest explanation: it is an easy way to avoid writing the Pyramid of Doom
  • 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. 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. 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. Is That Not Good Enough?var later = Q.nfcall(nodedc.wait_a_few_slides); // or: we’ll come back to it
  • 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. 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. Promises provide a solid abstraction for representing the state of an asynchronous call and writing flow ofcontrol code based on that state
  • 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. 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. 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. later.then(function(){Provides separation of concerns between wrapping and flow of control handling of deferred activities // that separation is the key });
  • 14. Promises can (mostly) be shared across libraries
  • 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. 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. Generating Promises With Q
  • 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. 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. 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. Control Flow and Error Handling
  • 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. 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. Testing
  • 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. 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. Resources• Q javascript library: https://github.com/kriskowal/q• Q documentation: http://documentup.com/kriskowal/q/
  • 28. Thank you. Questions?