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.

37e81bec5fcef8f12c61537c86ab1488?s=128

Bruno Lara Tavares

April 24, 2013
Tweet

Transcript

  1. Callbacks are calling back!

  2. Anatomy of a callback

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

    some stuff now that click happened */! });!
  4. NodeJS: Evented IO

  5. 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
  6. Now we know the reasons to use a callback… Let’s

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

    { /* do http request */ });! ! handleUserInterface();! putValuesOnTheFields(data.getValue()); !
  8. 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()! !
  9. 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/
  10. 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.)
  11. 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! })!
  12. 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/
  13. 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.
  14. Example of a Promise implementation https://github.com/tildeio/rsvp.js/blob/ master/lib/rsvp/promise.js

  15. Ok… So how can promises improve my code? Lets see

    some code then.
  16. 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!
  17. 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);! }!
  18. 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);! }!
  19. 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")! !
  20. 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")!
  21. 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 (:
  22. Things  you  think  are  important  to  say  

  23. Thanks!  contato@bltavares.com   GitHub Twitter

  24. Links •  http://userserve-ak.last.fm/serve/_/63480291/Back+to+the+Future +ChristopherLloydBacktotheFutur.jpg •  http://us.123rf.com/400wm/400/400/luislouro/luislouro0912/ luislouro091200086/6033163-businessman-back-making-a-call-by- cellphone-isolated-in-a-white-background.jpg •  http://i.qkme.me/3tdh8v.jpg

    •  https://encrypted-tbn3.gstatic.com/images? q=tbn:ANd9GcSMW5X93wxdF_3qmNLFCWFSHkDEmTmGr_8KTFzgTK_TOl Dm3NU4