You promise?
By Volodymyr Pavlyuk
Volodymyr Pavlyuk
• Almost 10 years in software development industry
• Web UI expert at SoftServe
Facebook: www.facebook.c...
Warning!
This presentation contains programming
code.
No cats beyond this point!
The Problem
Asynchronous JavaScript
APIs
// Synchronous
var contents = readFile('file.txt');
// …becomes
readFile('file.txt', function...
Error handling is ugly
readFile('file.txt', function(err, contents) {
if (error) {
handleError();
} else {
// do something...
You can’t throw!
readFile('file.txt', function(err, contents) {
if (error) throw error; // <- no one will catch it
});
You can’t throw!
function causeException() {
something.prop; // <- this causes exception
}
try {
setTimeout(function() {
c...
Chaining
getUser("UserName", function (user) {
getBestFriend(user, function (friend) {
ui.showBestFriend(friend);
});
});
Even worse with error
handling
getUser("UserName", function (err, user) {
if (err) {
ui.error(err);
} else {
getBestFriend...
Callbacks are hell
• No return
• No throw
• No consistency in callback API’s
• No guarantees: callback can be called
once,...
Callbacks are a hack
• They are literally the simplest thing that could
work.
• But as a replacement for synchronous contr...
Any solution?
Promises/A+
Promises are the right
abstraction
Instead of calling a passed callback, return a
promise:
readFile('file.txt', function(e...
A promise is an
ASYNCHRONOU
S value
Promise guarantees
var promiseForResult = readFile(“file.txt”);
promiseForResult.then(
function onFulfilled(result) {
// P...
https://github.com/promises-
aplus/promises-spec
promiseForResult.then(onFulfilled, onRejected);
• Only one of onFulfilled...
Promises can be chained
var transformedPromise = originalPromise.then(onFulfilled,
onRejected);
• If the called handler re...
Keep The Sync ⇔ Async Parallel In
Mind
Simple Functional Transform
var user = getUser();
var userName = user.name;
// becomes
var userNamePromise = getUser().the...
Reacting with an Exception
var user = getUser();
if (user === null)
throw new Error("null user!");
//becomes
var userPromi...
Handling an Exception
try {
deliverPizzaTo(tweet, 'volopav');
} catch (error) {
handleError(error);
}
// becomes
deliverPi...
Rethrowing an Exception
try {
var user = getUser('volopav');
} catch (error) {
throw new Error('ERROR: ' + error.message);...
Chaining
getUser("volopav", function (user) {
getBestFriend(user, function (friend) {
ui.showBestFriend(friend);
});
});
/...
Promises as First-Class
Objects
Because promises are first-class objects, you can build simple
operations on them instead ...
Promise Patterns: all + spread
all([getUser(), getCompany()]).then(function (results) {
console.log("user = ", results[0])...
Promise Patterns:
try/catch/finally
ui.startSpinner();
getUser("volopav")
.then(getBestFriend)
.then(ui.showBestFriend)
.c...
Promise Patterns: map + all
var userIds = ["123", "456", "789"];
all(userIds.map(getUserById))
.then(function (users) {
co...
This is looking nice, but I don’t
have APIs which return
promises?
Choose a Library
Best implementations:
• Q, by Kris Kowal and Domenic:
https://github.com/kriskowal/q
• When.js, by Brian ...
$.Deferred
• jQuery’s $.Deferred is a very buggy attempted
implementation, that entirely misses the sync ⇔ async
parallel
...
function getUser(name) {
var defer = Q.defer();
ajax(url, {name: name}, function(err, response) {
if (err) {
defer.reject(...
Denodify
var readFile = Q.denodeify(fs.readFile);
var readDir = Q.denodeify(fs.readdir);
readDir("/tmp")
.get("0")
.then(r...
ES6 native support of
promises
http://www.html5rocks.com/en/tutorials/es6/promi
ses/
So native APIs will return promises!
Keep The Sync ⇔ Async Parallel In
Mind
• Use promises for single operations that can result in fulfillment
( returning a v...
Promises Are Not
• A replacement for events
• A replacement for streams
• A way of doing functional reactive programming
T...
Questions?
You promise?
Upcoming SlideShare
Loading in …5
×

You promise?

829 views

Published on

by Volodymyr Pavlyuk

Published in: Software
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
829
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
4
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

You promise?

  1. 1. You promise? By Volodymyr Pavlyuk
  2. 2. Volodymyr Pavlyuk • Almost 10 years in software development industry • Web UI expert at SoftServe Facebook: www.facebook.com/volopav You can even follow me on Instagram – @volopav
  3. 3. Warning! This presentation contains programming code.
  4. 4. No cats beyond this point!
  5. 5. The Problem
  6. 6. Asynchronous JavaScript APIs // Synchronous var contents = readFile('file.txt'); // …becomes readFile('file.txt', function(err, contents) { // Process result here // Note, that there is no return });
  7. 7. Error handling is ugly readFile('file.txt', function(err, contents) { if (error) { handleError(); } else { // do something with contents } });
  8. 8. You can’t throw! readFile('file.txt', function(err, contents) { if (error) throw error; // <- no one will catch it });
  9. 9. You can’t throw! function causeException() { something.prop; // <- this causes exception } try { setTimeout(function() { causeException(); }, 0); } catch (e) { console.log(e); // <- will never get here }
  10. 10. Chaining getUser("UserName", function (user) { getBestFriend(user, function (friend) { ui.showBestFriend(friend); }); });
  11. 11. Even worse with error handling getUser("UserName", function (err, user) { if (err) { ui.error(err); } else { getBestFriend(user, function (err, friend) { if (err) { ui.error(err); } else { ui.showBestFriend(friend); } }); } });
  12. 12. Callbacks are hell • No return • No throw • No consistency in callback API’s • No guarantees: callback can be called once, multiple times or not called at all
  13. 13. Callbacks are a hack • They are literally the simplest thing that could work. • But as a replacement for synchronous control flow, they suck. • We lose the flow of our code writing callbacks that tie together other callbacks.
  14. 14. Any solution? Promises/A+
  15. 15. Promises are the right abstraction Instead of calling a passed callback, return a promise: readFile('file.txt', function(err, contents) { // Process result here }); // becomes var promiseForContents = readFile("file.txt");
  16. 16. A promise is an ASYNCHRONOU S value
  17. 17. Promise guarantees var promiseForResult = readFile(“file.txt”); promiseForResult.then( function onFulfilled(result) { // Precess result }, function onRejected(reason) { // handle error } );
  18. 18. https://github.com/promises- aplus/promises-spec 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.
  19. 19. 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.
  20. 20. Keep The Sync ⇔ Async Parallel In Mind
  21. 21. Simple Functional Transform var user = getUser(); var userName = user.name; // becomes var userNamePromise = getUser().then(function (user) { return user.name; });
  22. 22. 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; });
  23. 23. Handling an Exception try { deliverPizzaTo(tweet, 'volopav'); } catch (error) { handleError(error); } // becomes deliverPizzaTo(tweet, 'volopav') .then(undefined, handleError)
  24. 24. Rethrowing an Exception try { var user = getUser('volopav'); } catch (error) { throw new Error('ERROR: ' + error.message); } // becomes getUser('volopav').then(undefined, function(error) { throw new Error('ERROR: ' + error.message); });
  25. 25. Chaining getUser("volopav", function (user) { getBestFriend(user, function (friend) { ui.showBestFriend(friend); }); }); // becomes getUser("volopav") .then(getBestFriend) .then(ui.showBestFriend, ui.showError)
  26. 26. 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"));
  27. 27. Promise Patterns: all + spread all([getUser(), getCompany()]).then(function (results) { console.log("user = ", results[0]); console.log("company = ", results[1]); }).done(); all([getUser(), getCompany()]).spread(function (user, company) { console.log("user = ", user); console.log("company = ", company); }).done();
  28. 28. Promise Patterns: try/catch/finally ui.startSpinner(); getUser("volopav") .then(getBestFriend) .then(ui.showBestFriend) .catch(ui.error) .finally(ui.stopSpinner) .done();
  29. 29. Promise Patterns: map + all var userIds = ["123", "456", "789"]; all(userIds.map(getUserById)) .then(function (users) { console.log("all the users: ", users); }) .done();
  30. 30. This is looking nice, but I don’t have APIs which return promises?
  31. 31. Choose a Library Best implementations: • Q, by Kris Kowal and Domenic: 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
  32. 32. $.Deferred • jQuery’s $.Deferred is a very buggy attempted implementation, that entirely misses the sync ⇔ async parallel • If you ever see a jQuery promise, kill it with fire: var realPromise = Q(jQueryPromise); var realPromise = when(jQueryPromise);
  33. 33. function getUser(name) { var defer = Q.defer(); ajax(url, {name: name}, function(err, response) { if (err) { defer.reject(err); } else { defer.resolve(response); } }); return defer.promise; }
  34. 34. Denodify 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();
  35. 35. ES6 native support of promises http://www.html5rocks.com/en/tutorials/es6/promi ses/ So native APIs will return promises!
  36. 36. 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.
  37. 37. 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
  38. 38. Questions?

×