Making Ajax Sexy, JSConf 2010
Upcoming SlideShare
Loading in...5
×
 

Making Ajax Sexy, JSConf 2010

on

  • 1,609 views

A look at Sequential Ajax patterns and the Sexy.js library.

A look at Sequential Ajax patterns and the Sexy.js library.

Statistics

Views

Total Views
1,609
Views on SlideShare
1,600
Embed Views
9

Actions

Likes
2
Downloads
20
Comments
0

1 Embed 9

http://www.slideshare.net 9

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • good afternoon welcome to making ajax sexy <br />
  • feel free to be geeky as we go along, my code is available on github <br />
  • Also, if you&#x2019;d like to read some hastily scribed documentation, i have a website at sexyjs.com, but i have to warn you ... <br />
  • it&#x2019;s been deemed too risque for the workplace... <br />
  • by this guy... if you think it&#x2019;s NSFW but still want to try it <br />
  • i&#x2019;ve prepared another website for you <br />
  • i&#x2019;ve prepared another website for you <br />
  • it&#x2019;s even compatible with navigator 4. <br />
  • <br />
  • <br />
  • okay... let me look at my notes for a second <br />
  • okay... let me look at my notes for a second <br />
  • OK. Let&#x2019;s begin. Some of you might remember me from jsconf.eu. For those that don&#x2019;t, my name is Dave Furfero. I&#x2019;m a UI Engineer at MLB.com, long-time JavaScripter, long-form improviser, and all-around lovable guy. I&#x2019;m known as furf all around the world and the Internets. <br />
  • okay let&#x2019;s get started <br />
  • I&#x2019;ve come to talk to you about your never-ending thirst for asynchronous data, some Sequential Ajax patterns for loading and combining your data, and a little library I wrote called Sexy which makes it so so simple. <br />
  • I&#x2019;d guess that about 95% of the people in this room are working on the Internet&#x2019;s next killer app. I&#x2019;d also wager that 95% of those people are using Ajax to load data and that 95% of those people are loading data from more than one service. And I would venture that 95% of those people would like that data to interact in a meaningful way. <br />
  • <br />
  • As we work with a larger number and greater variety of data sources, and we&#x2019;re no longer served by the one request/one callback paradigm, we need to evolve new patterns for dealing with the unpredictability of Ajax. Sequential Ajax helps you mix and mash asynchronous data from various sources, local and remote, with predictable results. <br />
  • As we work with a larger number and greater variety of data sources, and we&#x2019;re no longer served by the one request/one callback paradigm, we need to evolve new patterns for dealing with the unpredictability of Ajax. Sequential Ajax helps you mix and mash asynchronous data from various sources, local and remote, with predictable results. <br />
  • <br />
  • And Sexy? Sexy makes it look good. Damn good. <br />
  • And Sexy? Sexy makes it look good. Damn good. <br />
  • <br />
  • Sequential Ajax is any of a number of patterns for writing Ajax that allow you to fire multiple requests, receive the data, and hopefully before they are finished allow you to meaningfully manipulate that data <br /> <br />
  • <br />
  • Sajax comes in three flavors. Two of them get the job done. One of them gets the job done Sexily <br />
  • <br />
  • Let&#x2019;s say we fire off three asynchronous requests, the server or servers do their thing, and send back the data. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • Let&#x2019;s say we fire off three asynchronous requests, the server or servers do their thing, and send back the data. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • Let&#x2019;s say we fire off three asynchronous requests, the server or servers do their thing, and send back the data. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • Let&#x2019;s say we fire off three asynchronous requests, the server or servers do their thing, and send back the data. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • Let&#x2019;s say we fire off three asynchronous requests, the server or servers do their thing, and send back the data. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • Let&#x2019;s say we fire off three asynchronous requests, the server or servers do their thing, and send back the data. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • Let&#x2019;s say we fire off three asynchronous requests, the server or servers do their thing, and send back the data. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • Let&#x2019;s say we fire off three asynchronous requests, the server or servers do their thing, and send back the data. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • Let&#x2019;s fire off three asynchronous requests, the server or servers do their thing, and send back the data. We have no control over the timing. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • Let&#x2019;s say we fire off three asynchronous requests, the server or servers do their thing, and send back the data. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • Let&#x2019;s say we fire off three asynchronous requests, the server or servers do their thing, and send back the data. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • Let&#x2019;s say we fire off three asynchronous requests, the server or servers do their thing, and send back the data. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • Let&#x2019;s say we fire off three asynchronous requests, the server or servers do their thing, and send back the data. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • Let&#x2019;s say we fire off three asynchronous requests, the server or servers do their thing, and send back the data. In this scenario, our data returns in the specified order and we execute each callback as soon as its data is available ready. Even if the others have yet to return. <br />
  • <br />
  • <br />
  • <br />
  • In this scenario, our servers will return the data out of order. Note how Callbacks B & C wait for the return of Callback A before firing. <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • Let&#x2019;s start by looking at some common anti-patterns and see if they look familiar. If they do, you may want to stick around... <br />
  • The first anti-pattern is serial request/serial response. Successive Ajax requests are nested inside callbacks and executed upon completion of the preceding request. Previous data is accessible to each callback via closure. WALKTHRU... <br />
  • <br />
  • The second anti-pattern is parallel request / random response. This pattern is quicker because requests are made simultaneously, but usually requires a counter and a common callback which is fired once all requests are complete. <br />
  • As I mentioned, this pattern is faster, but the code quickly grows bloated, crufty, and significantly harder to maintain. <br />
  • <br />
  • <br />
  • Sexy.js uses the 3rd Sajax pattern: parallel request/serial response. Requests made in parallel for speed and then by wrapping and eventing callback functions, Sexy ensures proper callback execution order every time. <br />
  • Originally written as a jQuery plugin, Sexy is now available as a standalone library using jQuery&#x2019;s Ajax. Yay, open source! Both the plugin and standalone pass jQuery as an adapter so I encourage anyone interested in porting Sexy to other libs to do so. I&#x2019;d be happy to help. <br />
  • Originally written as a jQuery plugin, Sexy is now available as a standalone library using jQuery&#x2019;s Ajax. Yay, open source! Both the plugin and standalone pass jQuery as an adapter so I encourage anyone interested in porting Sexy to other libs to do so. I&#x2019;d be happy to help. <br />
  • Sexy is a class. New Sexy chains can be constructed by calling new Sexy. And then requests can be made using the returned instance. <br />
  • Sexy is a class. New Sexy chains can be constructed by calling new Sexy. And then requests can be made using the returned instance. <br />
  • But I didn&#x2019;t think that was Sexy enough. So I did away with the new keyword. <br />
  • But I didn&#x2019;t think that was Sexy enough. So I did away with the new keyword. <br />
  • Let&#x2019;s look inside the Sexy constructor. Sexy checks the instanceof this, which if used with the new keyword would be Sexy. If it&#x2019;s not Sexy, then it was called without the new keyword, so we call it with the new keyword and return the new instance. <br />
  • Still not sexy enough! A Sexy object can also be instantiated just by calling any one of Sexy&#x2019;s instance methods as a static method of Sexy. (I just thought the extra parentheses were ugly.) <br />
  • Still not sexy enough! A Sexy object can also be instantiated by calling any one of Sexy&#x2019;s instance methods as a static method of Sexy. (I just thought the extra parentheses were ugly.) <br />
  • Looking back inside the code, you can see that we just loop the prototypal methods and add static methods that apply the desired method in the scope of a new Sexy instance. Since the API is 100% chainable, returning the method&#x2019;s return value, returns the instance. To which we can chain more calls. <br />
  • okay, let&#x2019;s take a look at Sexy&#x2019;s api. sexy was designed to be expressive and chainable so that the code looks like what the code does. <br />
  • okay, let&#x2019;s take a look at Sexy&#x2019;s api. sexy was designed to be expressive and chainable so that the code looks like what the code does. <br />
  • okay, let&#x2019;s take a look at Sexy&#x2019;s api. sexy was designed to be expressive and chainable so that the code looks like what the code does. <br />
  • A method for each supported data type. These types reflect the Sexy&#x2019;s jQuery roots with the exception of style, which adds stylesheet support and was added for &#x201C;completeness&#x201D;. Helpful when bootstrapping an app w Sexy. Script and Style have aliases, js and css. This is the shorthand form, and takes a URL and a callback as arguments. <br />
  • An optional 2nd argument will let you defer the request until the previous request has completed. You will see in a few slides how this allows us to handle server authentication and modify successive requests. <br />
  • In its verbose form, each method can also take a jQuery-like configuration object, for when you want to POST data or add an error callbacks, etc. Defer is also a configurable property of the configuration object <br />
  • look up dummy :) <br />
  • <br />
  • Here we can see two calls being chained. The requests are made simultaneously and the callbacks executed in the specified order. This is an example of the verbose syntax using configuration objects. Note the second argument of the second callback. <br />
  • This is how Sexy shares data. The return value of a success callback is cached when it is fired and then appended to the arguments of the following success callback when it is ready. <br />
  • But big configuration objects aren&#x2019;t always sexy. So here&#x2019;s the brief syntax which takes url and callback. <br />
  • Once again note the sharing of article between callbacks. But notice how we&#x2019;re just returning article. THis seems like something we&#x2019;ll do quite frequently, so... <br />
  • Sexy provides implicit callbacks. If you do not specify a callback, a pass thru function will be used to pass your results immediately to the next callback. <br />
  • Note article just automagically appears as an argument to our second callback. <br />
  • Since scripts and styles don&#x2019;t usually bring back data we want to interpret, if there is no callback, we pass thru the return value of the previous callback. <br /> You can stack as many as you want in there and the article will still get through. (of course that decreases the readability and should be avoided) <br />
  • Using defer we can force subsequent calls to behave in a serial request/serial response pattern, but we still benefit from the enhanced data availablility. Once logged in, we get the article, we can then manipulate it and pass it to the next request as its data property for posting before logging out. <br />
  • Sexy (like jQuery) loads local scripts as text and inserts them into the DOM, so managing script dependencies is as easy as writing a grocery list, a Secy grocery list. <br />
  • now its time for a Sexy Sajax makeover... <br />
  • Remember our parallel request / random response anti-pattern? Let&#x2019;s add a little sexy... <br />
  • and voila! all rise for your royal hotness. <br />
  • <br />
  • <br />
  • <br />
  • Here you can see that we want to display a loading indicator while the article loads, but its not so important while the comments load, so by passing any falsy value you can unset the previous config <br />
  • you can save yourself some keystrokes by passing your initial setup to the constructor <br />
  • Sexy also provides a sort of client-side Javascript packaging tool called Sexy.bundle... <br />
  • Bundle makes multiple requests and a single DOM insertion and then executes an optional callback. Because of the way sexy is designed, the script sequence and therefore your dependencies are preserved. <br />
  • Bundle makes multiple requests and a single DOM insertion and then executes an optional callback. Because of the way sexy is designed, the script sequence and therefore your dependencies are preserved. <br />
  • Bundle makes multiple requests and a single DOM insertion and then executes an optional callback. Because of the way sexy is designed, the script sequence and therefore your dependencies are preserved. <br />
  • Bundle makes multiple requests and a single DOM insertion and then executes an optional callback. Because of the way sexy is designed, the script sequence and therefore your dependencies are preserved. <br />
  • Bundle makes multiple requests and a single DOM insertion and then executes an optional callback. Because of the way sexy is designed, the script sequence and therefore your dependencies are preserved. <br />
  • Bundle makes multiple requests and a single DOM insertion and then executes an optional callback. Because of the way sexy is designed, the script sequence and therefore your dependencies are preserved. <br />
  • Bundle makes multiple requests and a single DOM insertion and then executes an optional callback. Because of the way sexy is designed, the script sequence and therefore your dependencies are preserved. <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />

Making Ajax Sexy, JSConf 2010 Making Ajax Sexy, JSConf 2010 Presentation Transcript

  • Making Ajax Sexy A Look at Sequential Ajax Patterns
  • View source http://github.com/furf/Sexy
  • Go to website… http://sexyjs.com View slide
  • NSFW? View slide
  • ?SFW
  • But really, “assholes?”
  • WARNING This presentation contains a very bawdy joke.
  • WARNING If very bawdy jokes are the sort of thing that offend you or make you uncomfortable in the trousers, you might want to leave now.
  • David Furfero @furf UI Engineer, MLB.com
  • SERIOUSLY Go, now.
  • YOU  DATA
  • Ajax makes killer web apps possible.
  • Sequential Ajax makes Ajax killer.
  • Sequential Ajax makes Ajax killer.
  • Sexy.js makes Sequential Ajax…Sexy!
  • Sexy.js makes Sequential Ajax…Sexy!
  • Sequential Ajax (Sajax) An Ajax pattern for handling multiple asynchronous requests while maintaining proper callback execution order.
  • Goals of Sequential Ajax (Sajax) • Facilitate combination and manipulation of data from multiple sources • Speed loading of data, scripts, stylesheets using parallel asynchronous HTTP requests • Speed execution of callbacks by allowing them to fire as soon as all previous data is available • Fun
  • Three Flavors of Sajax • Serial request / serial response • Parallel request / random response • Parallel request / serial response
  • In a perfect world…
  • In a world, where time waits for no man…
  • or his data…
  • Sequential Ajax Anti-Patterns
  • Serial Request / Serial Response // Request an article $.getJSON('/article/1.json', function (article) { // Request the related comments $.getJSON('/article/1/comments.json', function (comments) { // Join the data article.comments = comments; // Render the article and comments render(article); }); });
  • Serial Request / Serial Response • Pros • Relatively readable • Cons • Slower • Nested calls don’t scale
  • Parallel Request / Random Response var i = 0, n = 2, article, comments; $.getJSON('/article/1.json', function (data) { article = data; if (++i == n) { handleComplete(); } }); $.getJSON('/article/1/comments.json', function (data) { comments = data; if (++i == n) { handleComplete(); } }); function handleComplete () { article.comments = comments; render(article); }
  • Parallel Request / Random Response • Pros • Faster • Cons • Heavier • Uglier • Really doesn’t scale
  • Do those patterns look familiar?
  • Meet Sexy.js…
  • Sexy is a jQuery plugin A lightweight JavaScript library which provides parallel request/serial response Sequential Ajax (Sajax) functionality and a sleek facade to jQuery’s native Ajax methods.
  • Sexy is a standalone library A lightweight JavaScript library which provides parallel request/serial response Sequential Ajax (Sajax) functionality and a sleek facade to jQuery’s native Ajax methods JavaScript.
  • Sexy is a standalone library A lightweight JavaScript library which provides parallel request/serial response Sequential Ajax (Sajax) functionality and a sleek facade to jQuery’s native Ajax methods JavaScript (using jQuery’s native Ajax methods).
  • Sexy is classy new Sexy() creates a Sexy instance
  • Sexy is classy var s = new Sexy(); s.json(articleUrl, callback) .json(commentsUrl, callback);
  • Sexy is the new Sexy Sexy() also creates a Sexy instance
  • Sexy is the new Sexy Sexy() .json(articleUrl, callback) .json(commentsUrl, callback);
  • Naked Sexy /** * Constructs a new Sexy instance */ function Sexy (cfg) { /** * Allow instantiation without new keyword */ if (!(this instanceof Sexy)) { return new Sexy(cfg); } this.cfgs = []; this.setup(cfg); }
  • Sexy is full of surprises Sexy.fn() also creates a Sexy instance!
  • Sexy is full of surprises Sexy .json(articleUrl, callback) .json(commentsUrl, callback);
  • Naked Sexy /** * Add sexier static methods */ function addStaticMethod (method) { Sexy[method] = function () { return Sexy.prototype[method].apply(new Sexy(), arguments); }; } for (i in Sexy.prototype) { addStaticMethod(i); }
  • I WASN’T KIDDING! There is a bawdy joke coming up VERY soon!
  • I WASN’T KIDDING! If you are pregnant, have a serious heart condition, or giggle uncontrollably at the word “titillate”, you may want to hurry to Track A.
  • Expressive, Chainable API
  • Sexy is Your Syntactic Sugar Mama An expressive method for each supported data type: html (url, callback) json (url, callback) jsonp (url, callback) script / js (url, callback) text (url, callback) xml (url, callback) style / css (url, callback)
  • Sexy is Patient Requests can be deferred using an optional 2nd argument. html (url, defer, callback) json (url, defer, callback) jsonp (url, defer, callback) script / js (url, defer, callback) text (url, defer, callback) xml (url, defer, callback) style / css (url, defer, callback)
  • Sexy is Flexible Each method can also take a jQuery settings object. html (settings) json (settings) jsonp (settings) script / js (settings) text (settings) xml (settings) style / css (settings)
  • callback (data, previous, next, status) Each callback receives four arguments: data response data of the current request previous return value of the previous callback next Ajax settings of the next request status result status of the current request
  • Sexy Sequential Ajax Patterns
  • Sexy Sexy .json({ url: '/article/1.json', success: function (article) { return article; } }) .json({ url: '/article/1/comments.json', success: function (comments, article) { article.comments = comments; render(article); } });
  • Passing Data with Callbacks Sexy .json({ url: '/article/1.json', success: function (article, previous, next, status) { return article; } }) .json({ url: '/article/1/comments.json', success: function (comments, article, next, status) { article.comments = comments; render(article); } });
  • Sexy-er Sexy .json('/article/1.json', function (article) { return article; }) .json('/article/1/comments.json', function (comments, article) { article.comments = comments; render(article); });
  • Passing Data with Callbacks Sexy .json('/article/1.json', function (article) { return article; }) .json('/article/1/comments.json', function (comments, article) { article.comments = comments; render(article); });
  • Sexy-est Sexy .json('/article/1.json') .json('/article/1/comments.json', function (comments, article) { article.comments = comments; render(article); });
  • Passing Data with Implicit Callbacks Sexy .json('/article/1.json') .json('/article/1/comments.json', function (comments, article) { article.comments = comments; render(article); });
  • Passing Data with Implicit Callbacks Sexy .json('/article/1.json') .js('jquery.js') .json('/article/1/comments.json', function (comments, article) { article.comments = comments; render(article); });
  • Slow it Down Sexy // Authenticate user .json({ type: 'POST', url: 'login', data: { username: 'furf', password: '2s3xy4u' } }) // GET article .json('article/1', true, function (article, previous, nextCfg) { article.author = 'furf'; nextCfg.data = article; }) // POST article .json({ defer: true, type: 'POST', url: 'article/1' }) // De-authenticate user .json('logout', true);
  • Manage <script> Dependencies Sexy .js('jquery.js') .js('jquery-ui.js') .js('jquery-ui-i18n.js') .js('jquery.template.js') .js('mlb.js') .js('mlb.tracking.js') .js('mlb.datagrid.js') .js('mlb.stats.js') .js('mlb.stats.util.js') .js('mlb.stats.widget.js') .js('mlb.stats.sortableplayers.js', function () { mlb.stats.SortablePlayers.init(); });
  • A Sexy Cinderella Story
  • Old and Busted var i = 0, n = 2, article, comments; $.getJSON('/article/1.json', function (data) { article = data; if (++i == n) { handleComplete(); } }); $.getJSON('/article/1/comments.json', function (data) { comments = data; if (++i == n) { handleComplete(); } }); function handleComplete () { article.comments = comments; render(article); }
  • Your Royal Hotness Sexy .json('/article/1.json') .json('/article/1/comments.json', function (comments, article) { article.comments = comments; render(article); });
  • The 4th Stage of Grief ACCEPTANCE There’s no way out now. Strap yourself in. Accept your fate. The bawdy joke is on its way.
  • Additional Methods
  • setup (settings) • Configure subsequent requests of a Sexy instance • Settings can be unset with setup()
  • setup (settings) Sexy .setup({ beforeSend: showLoadingIndicator complete: hideLoadingIndicator }) .json('article.json', diplayArticle) .setup() .json('comments.json', displayComments);
  • Sexy (settings) Sexy({ beforeSend: showLoadingIndicator complete: hideLoadingIndicator }) .json('article.json', diplayArticle) .setup() .json('comments.json', displayComments);
  • bundle (url1, url2, ..., callback) • Client-side JavaScript packaging • Multiple file, single <script> injection • Sequence is preserved
  • Why not Sexy.package?
  • JavaScript was too reserved.
  • *groan*
  • :) I told you it was bawdy!
  • bundle (url1, url2, ..., callback) • Client-side JavaScript packaging • Multiple file, single <script> injection • Sequence is preserved
  • bundle (url1, url2, ..., callback) Sexy.bundle( 'jquery.js', 'jquery-ui.js', 'jquery-ui-i18n.js', 'jquery.template.js', 'mlb.js', 'mlb.tracking.js', 'mlb.datagrid.js', 'mlb.stats.js', 'mlb.stats.util.js', 'mlb.stats.widget.js', 'mlb.stats.app.sortableplayers.js', function () { mlb.stats.app.SortablePlayers.init(); } );
  • The Kama Sutra of Sexy.js
  • var s = Sexy .js('jquery.min.js') .js('jquery.template.min.js') .css('friends.css') .text('friend.tpl') .json('friends.json', function (data, tpl) { // Send a new request for each friend (executed simultaneously) $.each(data.friends, function (i, friend) { s.json(friend.username + '.json', function (friend, friends) { // Push onto the previously returned array friends.push(friend); // Until the last friend, return the augmented array to the next callback if (i < data.friends.length - 1) { return friends; // When we reach the last friend, render the data and insert into the DOM } else { $.template(tpl, friends).appendTo('#friends'); } }); }); // Instantiate the friends array return []; });
  • Known Issues • Unable to detect error events for remote requests • jsonp (remoteUrl) • script (remoteUrl) • style (remoteUrl) • style (remoteUrl) fires the success callback even if the request was unsuccessful (ie. 404)
  • Parallel Request / Serial Response • Pros • Faster • Cleaner • Prettier • Cons • Sexy.js adds 1.4Kb–4.6Kb to your JavaScript library
  • Parallel Request / Serial Response • Pros • Faster • Cleaner • Prettier • Cons • Sexy.js adds 1.4Kb–4.6Kb to your JavaScript library
  • Can’t get enough? website http://sexyjs.com slideshow http://www.slideshare.net/furf download http://github.com/furf/Sexy twitter @sexyjs or @furf email furf@furf.com
  • @thanks! jsconf, voodootikigod, jquery, jeresig, jaubourg, dimak25, subchild, brandonaaron, yoni, jsconfeu, getify, maraksquires, attricetta, and you!