SlideShare a Scribd company logo
Promises, Promises
                     BY @DOMENIC
Domenic Denicola
•   http://domenic.me
•   https://github.com/domenic
•   https://npmjs.org/~domenic
•   http://slideshare.net/domenicdenicola

Things I’m doing:
• @esdiscuss on Twitter
• The Promises/A+ spec
• HTML5DevConf, NodePDX, NodeConf
                                            @DOMENIC
@DOMENIC
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
Promises are the right abstraction
Instead of calling a passed callback, return a promise:

 readFile("file.txt", function (err, result) {
     // continue here…
 });

// becomes

 var promiseForResult = readFile("file.txt");

                                                          @DOMENIC
Promise guarantees
promiseForResult.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
Promises can be chained
var 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
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
Case 1: Simple Functional Transform
 var user = getUser();
 var userName = user.name;

// becomes

 var userNamePromise = getUser().then(function (user) {
     return user.name;
 });


                                                          @DOMENIC
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
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
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
Bonus Async Case: Waiting
 var name = promptForNewUserName();
 updateUser({ name: name });
 refreshUI();

// becomes

 promptForNewUserName()
   .then(function (name) {
      return updateUser({ name: name });
   })
   .then(refreshUI);
                                           @DOMENIC
Promises Give You Back Exception Propagation
getUser("Domenic", function (user) {
    getBestFriend(user, function (friend) {
        ui.showBestFriend(friend);
    });
});




                                               @DOMENIC
Promises Give You Back Exception Propagation
getUser("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
Promises Give You Back Exception Propagation
getUser("Domenic")
  .then(getBestFriend)
  .then(ui.showBestFriend, ui.error);




                                               @DOMENIC
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 reject
all([getUserData(), getCompanyData()]);

// Fulfills as soon as either completes, or rejects if both reject
any([storeDataOnServer1(), storeDataOnServer2()]);

// If writeFile accepts promises as arguments, and readFile returns one:
writeFile("dest.txt", readFile("source.txt"));
                                                                           @DOMENIC
@DOMENIC
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
CommonJS Promises/A
• Inspired by early implementations: ref_send, Dojo, …
• But…
  ▫ Underspecified
  ▫ Missing key features
  ▫ Often misinterpreted




                                                         @DOMENIC
$.Deferred
jQuery’s $.Deferred is a very buggy attempted implementation, that
entirely 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
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!
• 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
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
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 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
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
Promises Are Not
• A replacement for events
• A replacement for streams
• A way of doing functional reactive programming

They 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
The Unhandled Rejection Pitfall
This hits the top of the stack:

 throw new Error("boo!");

This stays inert:

 var promise = doSomething().then(function () {
     throw new Error("boo!");
 });

                                                  @DOMENIC
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 explode

function getUserName() {
   return getUser().then(function (user) {
    return user.name;
   });
 }
 getUserName().then(function (userName) {
    console.log("User name: ", userName);
 }).done();                                                                   @DOMENIC
Promise Patterns: try/catch/finally
ui.startSpinner();
getUser("Domenic")
   .then(getBestFriend)
   .then(ui.showBestFriend)
   .catch(ui.error)
   .finally(ui.stopSpinner)
   .done();



                                      @DOMENIC
Promise Patterns: all + spread
Q.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
Promise Patterns: map + all
var userIds = ["123", "456", "789"];

Q.all(userIds.map(getUserById))
  .then(function (users) {
     console.log("all the users: ", users);
  })
  .done();


                                              @DOMENIC
Promise Patterns: message sending
var userData = getUserData();
userData
  .then(createUserViewModel)
  .invoke("setStatus", "loaded")
  .done();
userData
  .get("friends")
  .get("0")
  .get("name")
  .then(setBestFriendsNameInUI)
  .done();
                                    @DOMENIC
Promise Patterns: Denodeify
var 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
(Bonus round!)




                 @DOMENIC
Coroutines

    “Coroutines are computer program
components that generalize subroutines to
allow multiple entry points for suspending
     and resuming execution at certain
                locations.”
                                     @DOMENIC
Generators = Shallow Coroutines
function* fibonacci() {
  var [prev, curr] = [0, 1];
  while (true) {
    [prev, curr] = [curr, prev + curr];
    yield curr;
  }
}

for (n of fibonnaci()) {
  console.log(n);
}                                         @DOMENIC
http://taskjs.org/


task.js: Generators + Promises = Tasks
spawn(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
task.js Even Works on Exceptions
spawn(function* () {
  var user;
  try {
     user = yield getUser();
  } catch (err) {
     ui.showError(err);
     return;
  }

      ui.updateUser(user);
});
                                   @DOMENIC
Remote Promises
userPromise
  .get("friends")
  .get("0")
  .invoke("calculateFriendshipCoefficient")
  .then(displayInUI)
  .done();

What if … userPromise referred to a remote object?!

                                                      @DOMENIC
https://github.com/kriskowal/q-connection/



Q Connection
• Can connect to web workers, <iframe>s, or web sockets

var Q = require("q");
var Connection = require("q-comm");
var remote = Connection(port, local);

// a promise for a remote object!
var userPromise = remote.getUser();


                                                                        @DOMENIC
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
• 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, and
What’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

More Related Content

What's hot (20)

PDF
Understanding Reactive Programming
Andres Almiray
 
PDF
Angular state Management-NgRx
Knoldus Inc.
 
PDF
Real Life Clean Architecture
Mattia Battiston
 
PDF
Collectors in the Wild
José Paumard
 
PDF
Clean Architecture
Badoo
 
PPTX
Java 8 Lambda and Streams
Venkata Naga Ravi
 
PPTX
Whitebox testing of Spring Boot applications
Yura Nosenko
 
PDF
Java ArrayList Tutorial | Edureka
Edureka!
 
PPT
Jsp/Servlet
Sunil OS
 
PPTX
Akka Actor presentation
Gene Chang
 
PDF
ReactJS presentation
Thanh Tuong
 
PDF
Cloud Native Java GraalVM 이상과 현실
Taewan Kim
 
PDF
Basics of React Hooks.pptx.pdf
Knoldus Inc.
 
PDF
Coroutines for Kotlin Multiplatform in Practise
Christian Melchior
 
PPT
Singleton design pattern
11prasoon
 
PDF
Introduction to RxJS
Brainhub
 
PPT
Ajax Ppt 1
JayaPrakash.m
 
PDF
Introduction to Java 11
Knoldus Inc.
 
PPTX
Understanding react hooks
Maulik Shah
 
PDF
Using MongoDB as a high performance graph database
Chris Clarke
 
Understanding Reactive Programming
Andres Almiray
 
Angular state Management-NgRx
Knoldus Inc.
 
Real Life Clean Architecture
Mattia Battiston
 
Collectors in the Wild
José Paumard
 
Clean Architecture
Badoo
 
Java 8 Lambda and Streams
Venkata Naga Ravi
 
Whitebox testing of Spring Boot applications
Yura Nosenko
 
Java ArrayList Tutorial | Edureka
Edureka!
 
Jsp/Servlet
Sunil OS
 
Akka Actor presentation
Gene Chang
 
ReactJS presentation
Thanh Tuong
 
Cloud Native Java GraalVM 이상과 현실
Taewan Kim
 
Basics of React Hooks.pptx.pdf
Knoldus Inc.
 
Coroutines for Kotlin Multiplatform in Practise
Christian Melchior
 
Singleton design pattern
11prasoon
 
Introduction to RxJS
Brainhub
 
Ajax Ppt 1
JayaPrakash.m
 
Introduction to Java 11
Knoldus Inc.
 
Understanding react hooks
Maulik Shah
 
Using MongoDB as a high performance graph database
Chris Clarke
 

Viewers also liked (20)

PDF
JavaScript Promise
Joseph Chiang
 
PDF
Boom! Promises/A+ Was Born
Domenic Denicola
 
PDF
Callbacks, promises, generators - asynchronous javascript
Łukasz Kużyński
 
PPTX
JavaScript on the Desktop
Domenic Denicola
 
PDF
JavaScript - new features in ECMAScript 6
Solution4Future
 
PDF
JavaScript Promises
우영 주
 
PPTX
The State of JavaScript (2015)
Domenic Denicola
 
PPTX
How to Win Friends and Influence Standards Bodies
Domenic Denicola
 
PDF
JavaScript Promises
Tomasz Bak
 
PPTX
Promises
Amal Haque
 
PPTX
Present Simple With Future Meaning
josealmaraz1999
 
PPT
Talking about the Future using Present Tenses
theLecturette
 
PPTX
Promises Javascript
Julien CROUZET
 
PPTX
Real World Windows 8 Apps in JavaScript
Domenic Denicola
 
PPTX
ES6 is Nigh
Domenic Denicola
 
PPTX
Creating Truly RESTful APIs
Domenic Denicola
 
PPT
Present tense verbs with future meaning
maleja2028
 
PPTX
The Final Frontier
Domenic Denicola
 
PPTX
Client-Side Packages
Domenic Denicola
 
DOCX
Importance of contract in Islam and legal importance
Muhammad Zeeshan Baloch
 
JavaScript Promise
Joseph Chiang
 
Boom! Promises/A+ Was Born
Domenic Denicola
 
Callbacks, promises, generators - asynchronous javascript
Łukasz Kużyński
 
JavaScript on the Desktop
Domenic Denicola
 
JavaScript - new features in ECMAScript 6
Solution4Future
 
JavaScript Promises
우영 주
 
The State of JavaScript (2015)
Domenic Denicola
 
How to Win Friends and Influence Standards Bodies
Domenic Denicola
 
JavaScript Promises
Tomasz Bak
 
Promises
Amal Haque
 
Present Simple With Future Meaning
josealmaraz1999
 
Talking about the Future using Present Tenses
theLecturette
 
Promises Javascript
Julien CROUZET
 
Real World Windows 8 Apps in JavaScript
Domenic Denicola
 
ES6 is Nigh
Domenic Denicola
 
Creating Truly RESTful APIs
Domenic Denicola
 
Present tense verbs with future meaning
maleja2028
 
The Final Frontier
Domenic Denicola
 
Client-Side Packages
Domenic Denicola
 
Importance of contract in Islam and legal importance
Muhammad Zeeshan Baloch
 
Ad

Similar to Promises, Promises (20)

PPT
You promise?
IT Weekend
 
PDF
Async js - Nemetschek Presentaion @ HackBulgaria
HackBulgaria
 
PPTX
The Promised Land (in Angular)
Domenic Denicola
 
PDF
Getting Comfortable with JS Promises
Asa Kusuma
 
PDF
Utilizing Bluebird Promises
Nicholas van de Walle
 
PDF
Promises, Promises: Mastering Async I/O in Javascript with the Promise Pattern
Christian Lilley
 
PDF
Promise is a Promise
Mateusz Bryła
 
PDF
Sane Async Patterns
TrevorBurnham
 
PDF
Javascript Promises
intive
 
PDF
Practical JavaScript Promises
Asa Kusuma
 
PDF
JavaScript - Promises study notes- 2019-11-30
YangJerng Hwa
 
PPTX
Avoiding callback hell in Node js using promises
Ankit Agarwal
 
PDF
4 mishchevskii - testing stage18-
Ievgenii Katsan
 
PDF
Promises are so passé - Tim Perry - Codemotion Milan 2016
Codemotion
 
PDF
Promises look into the async future
slicejs
 
PDF
Javascript Promises/Q Library
async_io
 
PDF
JavaScript Promises
Derek Willian Stavis
 
PDF
TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática
tdc-globalcode
 
PDF
Avoiding callback hell with promises
TorontoNodeJS
 
PDF
Kamil witecki asynchronous, yet readable, code
Kamil Witecki
 
You promise?
IT Weekend
 
Async js - Nemetschek Presentaion @ HackBulgaria
HackBulgaria
 
The Promised Land (in Angular)
Domenic Denicola
 
Getting Comfortable with JS Promises
Asa Kusuma
 
Utilizing Bluebird Promises
Nicholas van de Walle
 
Promises, Promises: Mastering Async I/O in Javascript with the Promise Pattern
Christian Lilley
 
Promise is a Promise
Mateusz Bryła
 
Sane Async Patterns
TrevorBurnham
 
Javascript Promises
intive
 
Practical JavaScript Promises
Asa Kusuma
 
JavaScript - Promises study notes- 2019-11-30
YangJerng Hwa
 
Avoiding callback hell in Node js using promises
Ankit Agarwal
 
4 mishchevskii - testing stage18-
Ievgenii Katsan
 
Promises are so passé - Tim Perry - Codemotion Milan 2016
Codemotion
 
Promises look into the async future
slicejs
 
Javascript Promises/Q Library
async_io
 
JavaScript Promises
Derek Willian Stavis
 
TDC2016POA | Trilha JavaScript - JavaScript Promises na Prática
tdc-globalcode
 
Avoiding callback hell with promises
TorontoNodeJS
 
Kamil witecki asynchronous, yet readable, code
Kamil Witecki
 
Ad

More from Domenic Denicola (11)

PPTX
Async Frontiers
Domenic Denicola
 
PPTX
The jsdom
Domenic Denicola
 
PPTX
ES6 in Real Life
Domenic Denicola
 
PPTX
Streams for the Web
Domenic Denicola
 
PPTX
After Return of the Jedi
Domenic Denicola
 
PPTX
The State of JavaScript
Domenic Denicola
 
PPTX
The Extensible Web
Domenic Denicola
 
PDF
ES6: The Awesome Parts
Domenic Denicola
 
PPTX
Domains!
Domenic Denicola
 
PDF
Unit Testing for Great Justice
Domenic Denicola
 
PDF
Understanding the Node.js Platform
Domenic Denicola
 
Async Frontiers
Domenic Denicola
 
The jsdom
Domenic Denicola
 
ES6 in Real Life
Domenic Denicola
 
Streams for the Web
Domenic Denicola
 
After Return of the Jedi
Domenic Denicola
 
The State of JavaScript
Domenic Denicola
 
The Extensible Web
Domenic Denicola
 
ES6: The Awesome Parts
Domenic Denicola
 
Unit Testing for Great Justice
Domenic Denicola
 
Understanding the Node.js Platform
Domenic Denicola
 

Recently uploaded (20)

PDF
Build with AI and GDG Cloud Bydgoszcz- ADK .pdf
jaroslawgajewski1
 
PDF
introduction to computer hardware and sofeware
chauhanshraddha2007
 
PDF
Per Axbom: The spectacular lies of maps
Nexer Digital
 
PDF
Generative AI vs Predictive AI-The Ultimate Comparison Guide
Lily Clark
 
PDF
TrustArc Webinar - Navigating Data Privacy in LATAM: Laws, Trends, and Compli...
TrustArc
 
PPTX
Agile Chennai 18-19 July 2025 | Workshop - Enhancing Agile Collaboration with...
AgileNetwork
 
PPTX
Dev Dives: Automate, test, and deploy in one place—with Unified Developer Exp...
AndreeaTom
 
PDF
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 
PDF
How ETL Control Logic Keeps Your Pipelines Safe and Reliable.pdf
Stryv Solutions Pvt. Ltd.
 
PDF
Brief History of Internet - Early Days of Internet
sutharharshit158
 
PDF
Integrating IIoT with SCADA in Oil & Gas A Technical Perspective.pdf
Rejig Digital
 
PDF
OpenInfra ID 2025 - Are Containers Dying? Rethinking Isolation with MicroVMs.pdf
Muhammad Yuga Nugraha
 
PDF
visibel.ai Company Profile – Real-Time AI Solution for CCTV
visibelaiproject
 
PDF
Market Wrap for 18th July 2025 by CIFDAQ
CIFDAQ
 
PPTX
PCU Keynote at IEEE World Congress on Services 250710.pptx
Ramesh Jain
 
PPTX
The Future of AI & Machine Learning.pptx
pritsen4700
 
PPTX
IT Runs Better with ThousandEyes AI-driven Assurance
ThousandEyes
 
PDF
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
PDF
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
PDF
CIFDAQ's Market Wrap : Bears Back in Control?
CIFDAQ
 
Build with AI and GDG Cloud Bydgoszcz- ADK .pdf
jaroslawgajewski1
 
introduction to computer hardware and sofeware
chauhanshraddha2007
 
Per Axbom: The spectacular lies of maps
Nexer Digital
 
Generative AI vs Predictive AI-The Ultimate Comparison Guide
Lily Clark
 
TrustArc Webinar - Navigating Data Privacy in LATAM: Laws, Trends, and Compli...
TrustArc
 
Agile Chennai 18-19 July 2025 | Workshop - Enhancing Agile Collaboration with...
AgileNetwork
 
Dev Dives: Automate, test, and deploy in one place—with Unified Developer Exp...
AndreeaTom
 
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 
How ETL Control Logic Keeps Your Pipelines Safe and Reliable.pdf
Stryv Solutions Pvt. Ltd.
 
Brief History of Internet - Early Days of Internet
sutharharshit158
 
Integrating IIoT with SCADA in Oil & Gas A Technical Perspective.pdf
Rejig Digital
 
OpenInfra ID 2025 - Are Containers Dying? Rethinking Isolation with MicroVMs.pdf
Muhammad Yuga Nugraha
 
visibel.ai Company Profile – Real-Time AI Solution for CCTV
visibelaiproject
 
Market Wrap for 18th July 2025 by CIFDAQ
CIFDAQ
 
PCU Keynote at IEEE World Congress on Services 250710.pptx
Ramesh Jain
 
The Future of AI & Machine Learning.pptx
pritsen4700
 
IT Runs Better with ThousandEyes AI-driven Assurance
ThousandEyes
 
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
CIFDAQ's Market Wrap : Bears Back in Control?
CIFDAQ
 

Promises, Promises

  • 1. Promises, Promises BY @DOMENIC
  • 2. Domenic Denicola • http://domenic.me • https://github.com/domenic • https://npmjs.org/~domenic • http://slideshare.net/domenicdenicola Things I’m doing: • @esdiscuss on Twitter • The Promises/A+ spec • HTML5DevConf, NodePDX, NodeConf @DOMENIC
  • 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. Promises are the right abstraction Instead of calling a passed callback, return a promise: readFile("file.txt", function (err, result) { // continue here… }); // becomes var promiseForResult = readFile("file.txt"); @DOMENIC
  • 6. Promise guarantees promiseForResult.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. Promises can be chained var 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. 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. Case 1: Simple Functional Transform var user = getUser(); var userName = user.name; // becomes var userNamePromise = getUser().then(function (user) { return user.name; }); @DOMENIC
  • 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. 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. 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. Bonus Async Case: Waiting var name = promptForNewUserName(); updateUser({ name: name }); refreshUI(); // becomes promptForNewUserName() .then(function (name) { return updateUser({ name: name }); }) .then(refreshUI); @DOMENIC
  • 14. Promises Give You Back Exception Propagation getUser("Domenic", function (user) { getBestFriend(user, function (friend) { ui.showBestFriend(friend); }); }); @DOMENIC
  • 15. Promises Give You Back Exception Propagation getUser("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. Promises Give You Back Exception Propagation getUser("Domenic") .then(getBestFriend) .then(ui.showBestFriend, ui.error); @DOMENIC
  • 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 reject all([getUserData(), getCompanyData()]); // Fulfills as soon as either completes, or rejects if both reject any([storeDataOnServer1(), storeDataOnServer2()]); // If writeFile accepts promises as arguments, and readFile returns one: writeFile("dest.txt", readFile("source.txt")); @DOMENIC
  • 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. CommonJS Promises/A • Inspired by early implementations: ref_send, Dojo, … • But… ▫ Underspecified ▫ Missing key features ▫ Often misinterpreted @DOMENIC
  • 21. $.Deferred jQuery’s $.Deferred is a very buggy attempted implementation, that entirely 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. All Was Quiet, Until… HORRIBLE LIES!! @DOMENIC
  • 23. I Got Angry @DOMENIC
  • 24. Then I Did Something About It @DOMENIC
  • 26. Then Things Got Awesome @DOMENIC
  • 27. Fast-Forward a Few Months… @DOMENIC
  • 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. 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
  • 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. 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. Promises Are Not • A replacement for events • A replacement for streams • A way of doing functional reactive programming They 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. The Unhandled Rejection Pitfall This hits the top of the stack: throw new Error("boo!"); This stays inert: var promise = doSomething().then(function () { throw new Error("boo!"); }); @DOMENIC
  • 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 explode function getUserName() { return getUser().then(function (user) { return user.name; }); } getUserName().then(function (userName) { console.log("User name: ", userName); }).done(); @DOMENIC
  • 36. Promise Patterns: try/catch/finally ui.startSpinner(); getUser("Domenic") .then(getBestFriend) .then(ui.showBestFriend) .catch(ui.error) .finally(ui.stopSpinner) .done(); @DOMENIC
  • 37. Promise Patterns: all + spread Q.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. Promise Patterns: map + all var userIds = ["123", "456", "789"]; Q.all(userIds.map(getUserById)) .then(function (users) { console.log("all the users: ", users); }) .done(); @DOMENIC
  • 39. Promise Patterns: message sending var userData = getUserData(); userData .then(createUserViewModel) .invoke("setStatus", "loaded") .done(); userData .get("friends") .get("0") .get("name") .then(setBestFriendsNameInUI) .done(); @DOMENIC
  • 40. Promise Patterns: Denodeify var 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. (Bonus round!) @DOMENIC
  • 42. Coroutines “Coroutines are computer program components that generalize subroutines to allow multiple entry points for suspending and resuming execution at certain locations.” @DOMENIC
  • 43. Generators = Shallow Coroutines function* fibonacci() { var [prev, curr] = [0, 1]; while (true) { [prev, curr] = [curr, prev + curr]; yield curr; } } for (n of fibonnaci()) { console.log(n); } @DOMENIC
  • 44. http://taskjs.org/ task.js: Generators + Promises = Tasks spawn(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. task.js Even Works on Exceptions spawn(function* () { var user; try { user = yield getUser(); } catch (err) { ui.showError(err); return; } ui.updateUser(user); }); @DOMENIC
  • 46. Remote Promises userPromise .get("friends") .get("0") .invoke("calculateFriendshipCoefficient") .then(displayInUI) .done(); What if … userPromise referred to a remote object?! @DOMENIC
  • 47. https://github.com/kriskowal/q-connection/ Q Connection • Can connect to web workers, <iframe>s, or web sockets var 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. 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. • 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, and What’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

Editor's Notes

  • #2: Hook: how many used promises?jQuery promises or real promises?Want to talk about this in three parts: a ground-up view of the promise abstraction; a historical perspective on recent developments; and a practical guide to using them in your code.
  • #5: What I really mean by this is “callback-accepting functions are a hack.”
  • #6: First benefit: separating outputs from inputs.
  • #7: - Consistency gains: never call back with more than one fulfillment value or rejection reason.
  • #8: Just like a series of imperative statements.
  • #22: And yet, we lived with it.
  • #28: Spec development process through GitHub issue trackerPull requests, implementers weighing in, bugs opened by randoms, etc.Test suite!
  • #32: Q has:Large, powerful API surfaceAdapters for Node.jsProgress supportSome support for long stack traces