Advertisement
Advertisement

More Related Content

Advertisement

Recently uploaded(20)

Advertisement

Javascript Promises/Q Library

  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 Doom step1(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 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/
  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 of control code based on that state
  10. Pyramid of Doom Again step1(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 Promises 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
  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 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)
  19. 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; };
  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 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
  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 mocha it('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?
Advertisement