Sane Async Patterns

  • View
    27.928

  • Download
    1

Embed Size (px)

DESCRIPTION

Talk given at HTML5DevConf on April 1, 2013.

Text of Sane Async Patterns

  • 1. Sane Async Patterns Trevor Burnham HTML5DevConf 2013
  • 2. http://dev.hubspot.com/jobs
  • 3. https://pragprog.com/books/tbcoffee
  • 4. https://pragprog.com/books/tbajs
  • 5. https://leanpub.com/npm
  • 6. In This Talk Callback arguments considered harmful Three alternative patterns: PubSub Promises AMD
  • 7. The Callback Argument Anti-Pattern
  • 8. Pyramid of DoommainWindow.menu("File", function(err, file) {if(err) throw err;file.openMenu(function(err, menu) {if(err) throw err;menu.item("Open", function(err, item) {if(err) throw err;item.click(function(err) {if(err) throw err;window.createDialog(DOOM!, function(err, dialog) {if(err) throw err;...});});});});});
  • 9. A JS-ers Lament// Synchronous version of previous slidetry { var file = mainWindow.menu("File");var menu = file.openMenu();var item = menu.item("Open");item.click()window.createDialog(DOOM!);} catch (err) { ...}
  • 10. A Silver LiningmyFunction1();// No state changes here!myFunction2();// Which means we never have to do this...while (!document.ready) { Thread.sleep(0);}
  • 11. Mo Threads...
  • 12. Nested SpaghettimainWindow.menu("File", function(err, file) {if(err) throw err;file.openMenu(function(err, menu) {if(err) throw err;menu.item("Open", function(err, item) {if(err) throw err;item.click(function(err) {if(err) throw err;window.createDialog(DOOM!, function(err, dialog) {if(err) throw err;...});});});});});
  • 13. Inexible APIsfunction launchRocketAt(target, callback) { var rocket = {x: 0, y: 0}, step = 0; function moveRocket() { rocket.x += target.x * (step / 10); rocket.y += target.y * (step / 10); drawSprite(rocket); if (step === 10) { callback(); } else { step += 1; setTimeout(moveRocket, 50); } } moveRocket();}
  • 14. Inexible APIslaunchRocketAt(target, function() { // OK, so the rocket reached its target...});
  • 15. Pattern I: PubSub
  • 16. What is PubSub?button.on("click", function(event) { ...});server.on("request", function(req, res, next) { ...});model.on("change", function() { ...});
  • 17. What is PubSub for? Just about everything! When in doubt, use PubSub
  • 18. How to use it? Pick a PubSub library, such as https://github.com/Wolfy87/EventEmitter If youre on Node, you already have one Simply make your objects inherit from EventEmitter, and trigger events on them
  • 19. An Evented RocketRocket.prototype.launchAt = function(target) { rocket = this; _.extend(rocket, {x: 0, y: 0, step: 0}); function moveRocket() { // Physics calculations go here... if (rocket.step === 10) { rocket.emit(complete, rocket); } else { rock.step += 1; setTimeout(moveRocket, 50); } rocket.emit(moved, rocket); } rocket.emit(launched, rocket); moveRocket(); return this;}
  • 20. An Evented Rocketvar rocket = new Rocket();rocket.launchAt(target).on(complete, function() { // Now its obvious what this callback is!});
  • 21. PubSub Drawbacks No standard Consider using LucidJS: https://github.com/RobertWHurst/ LucidJS
  • 22. Pattern II: Promises
  • 23. What is a Promise? A promise represents the eventual value returned from the single completion of an operation. The Promises/A Spec
  • 24. What is a Promise? An object that emits an event when an async task completes (or fails) Resolved Pending Rejected
  • 25. Example 1: Ajaxvar fetchingData = $.get(myData);fetchingData.done(onSuccess);fetchingData.fail(onFailure);fetchingData.state(); // pending// Additional listeners can be added at any timefetchingData.done(celebrate);// `then` is syntactic sugar for done + failfetchingData.then(huzzah, alas);
  • 26. Example 2: Effects$(#header).fadeTo(fast, 0.5).slideUp(fast);$(#content).fadeIn(slow);var animating = $(#header, #content).promise();animating.done(function() { // All of the animations started when promise() // was called are now complete.});
  • 27. What is a Promise? A promise is a container for an as-yet- unknown value, and thens job is to extract the value out of the promise http://blog.jcoglan.com/2013/03/30/ callbacks-are-imperative-promises-are- functional-nodes-biggest-missed- opportunity/
  • 28. Making Promises// A Promise is a read-only copy of a Deferredvar deferred = $.Deferred();asyncRead(function(err, data) { if (err) { deferred.reject(); } else { deferred.resolve(data); };});var Promise = deferred.promise();
  • 29. Without Promises$.fn.loadAndShowContent(function(options) { var $el = this; function successHandler(content) { $el.html(content); options.success(content); } function errorHandler(err) { $el.html(Error); options.failure(err); } $.ajax(options.url, { success: successHandler, error: errorHandler });});
  • 30. With Promises$.fn.loadAndShowContent(function(options) { var $el = this, fetchingContent = $.ajax(options.url); fetchingContent.done(function(content) { $el.html(content); }); fetchingContent.fail(function(content) { $el.html(Error); }); return fetchingContent;});
  • 31. Merging Promisesvar fetchingData = $.get(myData);var fadingButton = $button.fadeOut().promise();$.when(fetchingData, fadingButton) .then(function() { // Both Promises have resolved});
  • 32. Piping Promisesvar fetchingPassword = $.get(/password);fetchingPassword.done(function(password) { var loggingI