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.
Promises, Promises                     BY @DOMENIC
Domenic Denicola•   http://domenic.me•   https://github.com/domenic•   https://npmjs.org/~domenic•   http://slideshare.net...
@DOMENIC
Callbacks are a hack• They are literally the simplest thing that could work.• But as a replacement for synchronous control...
Promises are the right abstractionInstead of calling a passed callback, return a promise: readFile("file.txt", function (e...
Promise guaranteespromiseForResult.then(onFulfilled, onRejected);• Only one of onFulfilled or onRejected will be called.• ...
Promises can be chainedvar transformedPromise = originalPromise.then(onFulfilled, onRejected);• If the called handler retu...
The Sync ⇔ Async Parallel var result, threw = false; try {    result = doSomethingSync();   doSomethingAsync().then( } cat...
Case 1: Simple Functional Transform var user = getUser(); var userName = user.name;// becomes var userNamePromise = getUse...
Case 2: Reacting with an Exception var user = getUser(); if (user === null)    throw new Error("null user!");becomes var u...
Case 3: Handling an Exception try {    updateUser(data); } catch (ex) {    console.log("There was an error:", ex); }// bec...
Case 4: Rethrowing an Exception try {    updateUser(data); } catch (ex) {    throw new Error("Updating user failed. Detail...
Bonus Async Case: Waiting var name = promptForNewUserName(); updateUser({ name: name }); refreshUI();// becomes promptForN...
Promises Give You Back Exception PropagationgetUser("Domenic", function (user) {    getBestFriend(user, function (friend) ...
Promises Give You Back Exception PropagationgetUser("Domenic", function (err, user) {    if (err) {       ui.error(err);  ...
Promises Give You Back Exception PropagationgetUser("Domenic")  .then(getBestFriend)  .then(ui.showBestFriend, ui.error); ...
Promises as First-Class Objects• Because promises are first-class objects, you can build simple operations on  them instea...
@DOMENIC
Prehistory• “Discovered” circa 1989.• Much of modern promises are inspired by the E programming language.• They’ve made th...
CommonJS Promises/A• Inspired by early implementations: ref_send, Dojo, …• But…  ▫ Underspecified  ▫ Missing key features ...
$.DeferredjQuery’s $.Deferred is a very buggy attempted implementation, thatentirely misses the sync ⇔ async parallel:• Mu...
All Was Quiet, Until…                        HORRIBLE LIES!!                                          @DOMENIC
I Got Angry              @DOMENIC
Then I Did Something About It                                @DOMENIC
@DOMENIC
Then Things Got Awesome                          @DOMENIC
Fast-Forward a Few Months…                             @DOMENIC
I Think It’s Been a Success• >20 conformant implementations, with more showing up constantly  ▫ Even one in ActionScript 3...
Even the DOM and TC39 are getting in on this• Alex Russell’s DOMFuture promise library, for possibly using promises in  fu...
Some practical guidance                          @DOMENIC
First, Choose a Library• My top picks:  ▫ Q, by Kris Kowal and myself: https://github.com/kriskowal/q  ▫ When.js, by Brian...
Keep The Sync ⇔ Async Parallel In Mind• Use promises for single operations that can result in fulfillment  (⇔ returning a ...
Promises Are Not• A replacement for events• A replacement for streams• A way of doing functional reactive programmingThey ...
The Unhandled Rejection PitfallThis hits the top of the stack: throw new Error("boo!");This stays inert: var promise = doS...
Avoiding the Unhandled Rejection Pitfall• Always either:  ▫ return the promise to your caller;  ▫ or call .done() on it to...
Promise Patterns: try/catch/finallyui.startSpinner();getUser("Domenic")   .then(getBestFriend)   .then(ui.showBestFriend) ...
Promise Patterns: all + spreadQ.all([getUser(), getCompany()]).then(function (results) {   console.log("user = ", results[...
Promise Patterns: map + allvar userIds = ["123", "456", "789"];Q.all(userIds.map(getUserById))  .then(function (users) {  ...
Promise Patterns: message sendingvar userData = getUserData();userData  .then(createUserViewModel)  .invoke("setStatus", "...
Promise Patterns: Denodeifyvar readFile = Q.denodeify(fs.readFile);var readDir = Q.denodeify(fs.readdir);readDir("/tmp")  ...
(Bonus round!)                 @DOMENIC
Coroutines    “Coroutines are computer programcomponents that generalize subroutines toallow multiple entry points for sus...
Generators = Shallow Coroutinesfunction* fibonacci() {  var [prev, curr] = [0, 1];  while (true) {    [prev, curr] = [curr...
http://taskjs.org/task.js: Generators + Promises = Tasksspawn(function* () {    var data = yield $.ajax(url);    $("#resul...
task.js Even Works on Exceptionsspawn(function* () {  var user;  try {     user = yield getUser();  } catch (err) {     ui...
Remote PromisesuserPromise  .get("friends")  .get("0")  .invoke("calculateFriendshipCoefficient")  .then(displayInUI)  .do...
https://github.com/kriskowal/q-connection/Q Connection• Can connect to web workers, <iframe>s, or web socketsvar Q = requi...
Promise Pipelining• Usual “remote object” systems fall down in a few ways:  ▫ They would see the first request, and return...
• Start using promises in your code: client, server,                everywhere.              • Be aware that you want a Pr...
You’ve finished this document.
Download and read it offline.
Upcoming SlideShare
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript
Next
Upcoming SlideShare
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patterns in JavaScript
Next
Download to read offline and view in fullscreen.

Share

Promises, Promises

Download to read offline

An introduction to promises from the ground up; an overview of the recent history of promises; and some guidance on using promises in your real-world code.

Video at http://www.youtube.com/watch?v=MNxnHbyzhuo, and article at http://open.blogs.nytimes.com/2013/05/29/promises-promises/.

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

Promises, Promises

  1. 1. Promises, Promises BY @DOMENIC
  2. 2. Domenic Denicola• http://domenic.me• https://github.com/domenic• https://npmjs.org/~domenic• http://slideshare.net/domenicdenicolaThings I’m doing:• @esdiscuss on Twitter• The Promises/A+ spec• HTML5DevConf, NodePDX, NodeConf @DOMENIC
  3. 3. @DOMENIC
  4. 4. Callbacks are a hack• They are literally the simplest thing that could work.• But as a replacement for synchronous control flow, they suck.• There’s no consistency in callback APIs.• There’s no guarantees.• We lose the flow of our code writing callbacks that tie together other callbacks.• We lose the stack-unwinding semantics of exceptions, forcing us to handle errors explicitly at every step. @DOMENIC
  5. 5. Promises are the right abstractionInstead of calling a passed callback, return a promise: readFile("file.txt", function (err, result) { // continue here… });// becomes var promiseForResult = readFile("file.txt"); @DOMENIC
  6. 6. Promise guaranteespromiseForResult.then(onFulfilled, onRejected);• Only one of onFulfilled or onRejected will be called.• onFulfilled will be called with a single fulfillment value (⇔ return value).• onRejected will be called with a single rejection reason (⇔ thrown exception).• If the promise is already settled, the handlers will still be called once you attach them.• The handlers will always be called asynchronously. @DOMENIC
  7. 7. Promises can be chainedvar transformedPromise = originalPromise.then(onFulfilled, onRejected);• If the called handler returns a value, transformedPromise will be resolved with that value: ▫ If the returned value is a promise, we adopt its state. ▫ Otherwise, transformedPromise is fulfilled with that value.• If the called handler throws an exception, transformedPromise will be rejected with that exception. @DOMENIC
  8. 8. The Sync ⇔ Async Parallel var result, threw = false; try { result = doSomethingSync(); doSomethingAsync().then( } catch (ex) { process, threw = true; handle handle(ex); ); } if (!threw) process(result); @DOMENIC
  9. 9. Case 1: Simple Functional Transform var user = getUser(); var userName = user.name;// becomes var userNamePromise = getUser().then(function (user) { return user.name; }); @DOMENIC
  10. 10. Case 2: Reacting with an Exception var user = getUser(); if (user === null) throw new Error("null user!");becomes var userPromise = getUser().then(function (user) { if (user === null) throw new Error("null user!"); return user; }); @DOMENIC
  11. 11. Case 3: Handling an Exception try { updateUser(data); } catch (ex) { console.log("There was an error:", ex); }// becomes var updatePromise = updateUser(data).then(undefined, function (ex) { console.log("There was an error:", ex); }); @DOMENIC
  12. 12. Case 4: Rethrowing an Exception try { updateUser(data); } catch (ex) { throw new Error("Updating user failed. Details: " + ex.message); }// becomes var updatePromise = updateUser(data).then(undefined, function (ex) { throw new Error("Updating user failed. Details: " + ex.message); }); @DOMENIC
  13. 13. Bonus Async Case: Waiting var name = promptForNewUserName(); updateUser({ name: name }); refreshUI();// becomes promptForNewUserName() .then(function (name) { return updateUser({ name: name }); }) .then(refreshUI); @DOMENIC
  14. 14. Promises Give You Back Exception PropagationgetUser("Domenic", function (user) { getBestFriend(user, function (friend) { ui.showBestFriend(friend); });}); @DOMENIC
  15. 15. Promises Give You Back Exception PropagationgetUser("Domenic", function (err, user) { if (err) { ui.error(err); } else { getBestFriend(user, function (err, friend) { if (err) { ui.error(err); } else { ui.showBestFriend(friend); } }); }}); @DOMENIC
  16. 16. Promises Give You Back Exception PropagationgetUser("Domenic") .then(getBestFriend) .then(ui.showBestFriend, ui.error); @DOMENIC
  17. 17. Promises as First-Class Objects• Because promises are first-class objects, you can build simple operations on them instead of tying callbacks together:// Fulfills with an array of results, or rejects if any rejectall([getUserData(), getCompanyData()]);// Fulfills as soon as either completes, or rejects if both rejectany([storeDataOnServer1(), storeDataOnServer2()]);// If writeFile accepts promises as arguments, and readFile returns one:writeFile("dest.txt", readFile("source.txt")); @DOMENIC
  18. 18. @DOMENIC
  19. 19. Prehistory• “Discovered” circa 1989.• Much of modern promises are inspired by the E programming language.• They’ve made their way into many languages: ▫ .NET’s Task<T> ▫ java.util.concurrent.Future ▫ Python’s PEP 3148 ▫ C++ 11’s std::future @DOMENIC
  20. 20. CommonJS Promises/A• Inspired by early implementations: ref_send, Dojo, …• But… ▫ Underspecified ▫ Missing key features ▫ Often misinterpreted @DOMENIC
  21. 21. $.DeferredjQuery’s $.Deferred is a very buggy attempted implementation, thatentirely misses the sync ⇔ async parallel:• Multiple fulfillment values and rejection reasons• Only supports scenario 1 (functional transformation); doesn’t handle errors• Not interoperable with other “thenables.”• Before 1.8, did not support returning a promise @DOMENIC
  22. 22. All Was Quiet, Until… HORRIBLE LIES!! @DOMENIC
  23. 23. I Got Angry @DOMENIC
  24. 24. Then I Did Something About It @DOMENIC
  25. 25. @DOMENIC
  26. 26. Then Things Got Awesome @DOMENIC
  27. 27. Fast-Forward a Few Months… @DOMENIC
  28. 28. I Think It’s Been a Success• >20 conformant implementations, with more showing up constantly ▫ Even one in ActionScript 3!• The creation of RSVP.js specifically so that Ember could have Promises/A+ compatible promises• Version 1.1 of the spec almost ready, nailing down some unspecified points• Several other sibling specs under active development: promise creation, cancellation, progress, … @DOMENIC
  29. 29. Even the DOM and TC39 are getting in on this• Alex Russell’s DOMFuture promise library, for possibly using promises in future or existing DOM APIs• Convergence with Mark Miller’s concurrency strawman, for integrating promises into the language @DOMENIC
  30. 30. Some practical guidance @DOMENIC
  31. 31. First, Choose a Library• My top picks: ▫ Q, by Kris Kowal and myself: https://github.com/kriskowal/q ▫ When.js, by Brian Cavalier: https://github.com/cujojs/when ▫ RSVP.js, by Yehuda Katz: https://github.com/tildeio/rsvp.js• If you ever see a jQuery promise, kill it with fire: var realPromise = Q(jQueryPromise); var realPromise = when(jQueryPromise); @DOMENIC
  32. 32. Keep The Sync ⇔ Async Parallel In Mind• Use promises for single operations that can result in fulfillment (⇔ returning a value) or rejection (⇔ throwing an exception).• If you’re ever stuck, ask “how would I structure this code if it were synchronous?” ▫ The only exception is multiple parallel operations, which has no sync counterpart. @DOMENIC
  33. 33. Promises Are Not• A replacement for events• A replacement for streams• A way of doing functional reactive programmingThey work together:• An event can trigger from one part of your UI, causing the event handler to trigger a promise-returning function• A HTTP request function can return a promise for a stream @DOMENIC
  34. 34. The Unhandled Rejection PitfallThis hits the top of the stack: throw new Error("boo!");This stays inert: var promise = doSomething().then(function () { throw new Error("boo!"); }); @DOMENIC
  35. 35. Avoiding the Unhandled Rejection Pitfall• Always either: ▫ return the promise to your caller; ▫ or call .done() on it to signal that any unhandled rejections should explodefunction getUserName() { return getUser().then(function (user) { return user.name; }); } getUserName().then(function (userName) { console.log("User name: ", userName); }).done(); @DOMENIC
  36. 36. Promise Patterns: try/catch/finallyui.startSpinner();getUser("Domenic") .then(getBestFriend) .then(ui.showBestFriend) .catch(ui.error) .finally(ui.stopSpinner) .done(); @DOMENIC
  37. 37. Promise Patterns: all + spreadQ.all([getUser(), getCompany()]).then(function (results) { console.log("user = ", results[0]); console.log("company = ", results[1]);}).done();Q.all([getUser(), getCompany()]).spread(function (user, company) { console.log("user = ", user); console.log("company = ", company);}).done(); @DOMENIC
  38. 38. Promise Patterns: map + allvar userIds = ["123", "456", "789"];Q.all(userIds.map(getUserById)) .then(function (users) { console.log("all the users: ", users); }) .done(); @DOMENIC
  39. 39. Promise Patterns: message sendingvar userData = getUserData();userData .then(createUserViewModel) .invoke("setStatus", "loaded") .done();userData .get("friends") .get("0") .get("name") .then(setBestFriendsNameInUI) .done(); @DOMENIC
  40. 40. Promise Patterns: Denodeifyvar readFile = Q.denodeify(fs.readFile);var readDir = Q.denodeify(fs.readdir);readDir("/tmp") .get("0") .then(readFile) .then(function (data) { console.log("The first temporary file contains: ", data); }) .catch(function (error) { console.log("One of the steps failed: ", error); }) .done(); @DOMENIC
  41. 41. (Bonus round!) @DOMENIC
  42. 42. Coroutines “Coroutines are computer programcomponents that generalize subroutines toallow multiple entry points for suspending and resuming execution at certain locations.” @DOMENIC
  43. 43. Generators = Shallow Coroutinesfunction* fibonacci() { var [prev, curr] = [0, 1]; while (true) { [prev, curr] = [curr, prev + curr]; yield curr; }}for (n of fibonnaci()) { console.log(n);} @DOMENIC
  44. 44. http://taskjs.org/task.js: Generators + Promises = Tasksspawn(function* () { var data = yield $.ajax(url); $("#result").html(data); var status = $("#status").html("Download complete."); yield status.fadeIn().promise(); yield sleep(2000); status.fadeOut();}); @DOMENIC
  45. 45. task.js Even Works on Exceptionsspawn(function* () { var user; try { user = yield getUser(); } catch (err) { ui.showError(err); return; } ui.updateUser(user);}); @DOMENIC
  46. 46. Remote PromisesuserPromise .get("friends") .get("0") .invoke("calculateFriendshipCoefficient") .then(displayInUI) .done();What if … userPromise referred to a remote object?! @DOMENIC
  47. 47. https://github.com/kriskowal/q-connection/Q Connection• Can connect to web workers, <iframe>s, or web socketsvar Q = require("q");var Connection = require("q-comm");var remote = Connection(port, local);// a promise for a remote object!var userPromise = remote.getUser(); @DOMENIC
  48. 48. Promise Pipelining• Usual “remote object” systems fall down in a few ways: ▫ They would see the first request, and return the entire friends array. ▫ They can’t invoke methods that involved closed-over state, only methods that you can send over the wire. ▫ Workarounds involve complex serialization and rehydration approaches, i.e. require coupling the client and the server.• With promises as the abstraction, we can “pipeline” messages from one side to the other, returning the ultimately-desired result. @DOMENIC
  49. 49. • Start using promises in your code: client, server, everywhere. • Be aware that you want a Promises/A+ compatible library—beware jQuery. • Generators are almost ready in Firefox, Chrome, andWhat’s next Node.js. • Investigate promises for real-time communication with Q-Connection. • Look forward to promises in the DOM, and maybe some syntactic support in ECMAScript 7! @DOMENIC
  • sumitkatiyar

    Apr. 27, 2017
  • ssuser2f3602

    Dec. 10, 2016
  • dromo

    Apr. 29, 2016
  • GabrielFerraz6

    Apr. 4, 2016
  • ssuser611bac

    Jan. 4, 2016
  • BillBurleigh

    Dec. 3, 2015
  • ssuser354a69

    Sep. 20, 2015
  • earl1eszomb13

    Aug. 25, 2015
  • JachelLeonardoSamale

    Aug. 3, 2015
  • legume2

    May. 21, 2015
  • 3160586

    May. 4, 2015
  • gimi

    Apr. 7, 2015
  • coosuu

    Mar. 30, 2015
  • maciejjankowski2

    Mar. 3, 2015
  • arnoudbos

    Feb. 21, 2015
  • AdamPiper1

    Jan. 10, 2015
  • linedx

    Jan. 6, 2015
  • poudelarun

    Dec. 29, 2014
  • pa3kmihalcin

    Dec. 8, 2014
  • thinkpanda

    Nov. 17, 2014

An introduction to promises from the ground up; an overview of the recent history of promises; and some guidance on using promises in your real-world code. Video at http://www.youtube.com/watch?v=MNxnHbyzhuo, and article at http://open.blogs.nytimes.com/2013/05/29/promises-promises/.

Views

Total views

22,864

On Slideshare

0

From embeds

0

Number of embeds

1,337

Actions

Downloads

338

Shares

0

Comments

0

Likes

56

×