Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Callbacks are calling back

Callbacks are calling back

Nested callbacks get really cumbersome after a while. Let's see some alternatives for a better Future of JS.
I Promise it will make your js code nicer.

Avatar for Bruno Lara Tavares

Bruno Lara Tavares

April 24, 2013
Tweet

More Decks by Bruno Lara Tavares

Other Decks in Programming

Transcript

  1. var $as = $(“a”);! ! $as.on(“click”, function(e) {! /* do

    some stuff now that click happened */! });!
  2. Evented IO + CPS •  Processes happens as events happens

    – Waiting for a result is not feasible •  Continuing the process in the future –  Passing it to future processes
  3. Now we know the reasons to use a callback… Let’s

    see some different approaches to deal with future data
  4. Futures •  Deferred process handling var data = Future(function (handler)

    { /* do http request */ });! ! handleUserInterface();! putValuesOnTheFields(data.getValue()); !
  5. Broken implementation function Future(p) {! var value, finished;! finished =

    false;! process.nextTick(function() { p(function(result) { ! " "value = result;! " "finished = true; })});! ! return { ! getValue: function getValue() { ! if(!finished) {! console.log("not ready");! arguments.callee();! }! return value;! }! }! };! ! ! var p = Future(function(end) { setTimeout(function() { end(3); }, 1000) });! p.getValue()! !
  6. Working implementation of Future •  Async I/O + lack of

    threads makes it really complicated to use while loops in Javascript with background processes http://code.activestate.com/recipes/ 84317/
  7. Promises •  They are similar to Futures, in the sense

    of deferring execution. •  The interface allows you to create utility functions to combine and chain multiple promises •  (Shhhh! Promises are monads.)
  8. JQuery 1.5 ajax object var req = $.get('foo.htm');! ! req.done(function(response)

    {! // do something with the response! });! ! req.fail(function() {! // do something if the request failed! });! ! var lis = $(“li”);! req.done(function(response) {! // do more stuff with response and lis! })!
  9. Javascript community current state •  Node introduced the default api

    of: func(args…,callback(err,arrgs…))! ! •  Some libraries are handling the implementations of Promises •  They got into an agreement called Promises/ A+ –  http://promises-aplus.github.io/promises-spec/
  10. Promises/A+   •  General – A promise represents a value that

    may not be available yet. The primary method for interacting with a promise is its then method.
  11. Some context on Promises utilities •  We are going to

    show some code use the Q library https://github.com/kriskowal/q •  Q.nfbind :: (err -> result -> ()) -> Promise result! •  Q.all :: [Promise] -> Promise [Promise]! •  Q.spread :: [Promise] -> Promise args… -> Promise! •  This is not the exactly type signature, nor Haskell syntax, it is just similar!
  12. Some context on the code var render = console.log;! !

    var handleError = function(error) {! console.log("error");! console.log(error);! } ! ! var User = {};! User.find = function(id, callback) {! setTimeout(function() { ! "callback(Math.random() < 0.1, {id: id}); ! }, 1000);! }!
  13. var Fight = {};! Fight.calculateResult = function(user1, user2, callback) {!

    setTimeout(function() {! "callback(Math.random() < 0.1, {! " " " " " winner: user1,! " " " " " loser: user2 }) }! ,1000);! }! ! Fight.save = function(fight, callback) {! setTimeout(function() { ! "callback(Math.random() < 0.1, {! " " " " " "id: Math.random() * 100}) }! ,1000);! }!
  14. Callback style render("started")! User.find(1, function(err, user) {! if(err) { handleError(err);

    return; }! ! User.find(2, function(err2, user2) {! if(err2) { handleError(err2); return; }! ! Fight.calculateResult(user, user2, function(err3, fight){! if(err3) { handleError(err3); return; }! ! Fight.save(fight, function(err4, fight2){! if(err4) { handleError(err4); return; }! ! render(fight2);! });! });! });! })! render("ended")! !
  15. Promise style var Q = require("q")! var toPromise = Q.nfbind;!

    ! var userFind = toPromise(User.find);! var fightCalculateResult = toPromise(Fight.calculateResult);! var fightSave = toPromise(Fight.save);! ! render("started")! ! Q.all([userFind(1), userFind(2)])! .spread(fightCalculateResult)! .then(fightSave)! .then(render)! .fail(handleError)! ! render("ended")!
  16. Things I think it is important to say •  Expose

    api’s that uses the community style guide to maximize integration –  Expose func(args…, callback(err, arrgs…))! •  Use Promises internally to make future data interaction and flow more explicit •  Use callbacks when it makes sense (ie: click events…) •  Everything in excess is bad •  Try more functional approaches (: