Presentation is loading. Please wait.

Presentation is loading. Please wait.

JQuery: New Features and APIs 4-25-2012. 2 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Contents Introduction Deferred The New Event API.

Similar presentations


Presentation on theme: "JQuery: New Features and APIs 4-25-2012. 2 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Contents Introduction Deferred The New Event API."— Presentation transcript:

1 jQuery: New Features and APIs

2 2 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Contents Introduction Deferred The New Event API

3 3 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Introduction

4 4 © COPYRIGHT 2012 SAPIENT CORPORATION | CONFIDENTIAL Bio Rob Larsen Rob Larsen has more than 12 years’ experience as a front end engineer and team leader, building web sites and applications for some of the world’s biggest brands. He is currently a Senior Specialist, Platform at Sapient Global Markets. Rob is an active writer and speaker on web technology with a special focus on emerging standards like HTML5, CSS3 and the ongoing evolution of JavaScript. He’s written one book, Professional jQuery (WROX), and is working on two more. github: github.com/roblarsen. HTML + CSS + JavaScript

5 5 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Before we get started

6 6 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Yes. I wrote (half of) this book.

7 7 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL But… No. I’m not a complete jQuery fanboy.

8 8 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL That guy works at Groupon, btw He could probably buy John outright

9 9 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL #dumbjquerystuff I don’t always agree with what they do. And this isn’t just API nitpicks o Killing $.tmpl() without a completed replacement o Killing the entire plugin site without a replacement in place

10 10 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL I’m Still Skeptical I was basically forced into using it every day only a couple of years ago Stylistically, there are things I dislike about jQuery o Everything is an anonymous function. No code reuse Tightly coupled application logic Monolithic callbacks o I don’t believe less code or less characters always === better code Sometimes it’s great, but, not always. o A prime example is the $(function(){}) shortcut for $(document).ready(function(){}) One is clear, especially for beginners.

11 11 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Still, The New Stuff is Shiny. And New. Based on the code I see day-to-day, “new” is roughly defined as 1.5+ A couple of these are major and will make you better at your job Let’s look at what “new” means

12 12 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Significant New Features of jQuery o Rewrite of $.ajax() o Introduction of $.deferred() 1.6 o attr() (use for actual HTML attributes) and prop() (use for DOM properties) This broke stuff o $.holdReady( ) Manage the $.ready() event manually. 1.7 o $.on() and $.off() The one Event API to rule them all. o innerShivized versions of $.html(), etc. HTML5 magic

13 13 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Two Stand Out (For Me, At Least) Let’s look at some of this stuff in depth

14 14 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Advanced Asynchronous Programming with jQuery Deferred

15 15 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Defined $.Deferred, introduced in version 1.5, is a chainable utility object that provides fine-tuned control over the way callback functions are handled. For example, instead of merely having a single success method for your $.ajax calls, you can now define multiple callbacks that can be combined with precision and flexibility. No more: o Monolithic success blocks success : function(){ //10,000 lines later } o Unmaintainable function calls buried at the end of other function calls success : function(){ //10,000 lines later doSomethingElse(); }

16 16 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Promises/Promises Basically defined, a promise is a proxy for the result of an action that will happen at an unspecified time in the future. jQuery’s specific implementation is based on the Promises/A proposal from CommonJS. var promise = ajaxPromise() { //XHR request //state is set to fulfilled, unfulfilled, or failed //depending on the result of the request return state }; function unfulfilled(){ //handle negative result } function fulfilled() { //handle successful result } fucntion failed(){ //Error! } promise.then( unfulfilled, fulfilled, failed );

17 17 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL $.Deferred() jQuery’s implementation adds several useful enhancements. o Importantly, it integrates directly with $.ajax The format of the implementation is heavy on the ability to chain methods o It’s also written in a friendly, human-readable style.

18 18 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL $.when, Deferred.done, and Deferred.fail $.when accepts either one or more Deferred objects (which importantly include $.ajax calls) or a plain object. o If a Deferred is passed to $.when, its promise object is returned by the method. Deferred.done accepts a single function or array of functions to fire when a promise is resolved successfully. Deferred.fail also accepts a function or array of functions. It fires when a promise is rejected.

19 19 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL $.when, Deferred.done, and Deferred.fail function fib() { return $.Deferred(function() { var int1 = 0, int2 = 1, int3, sequence = " 0 1 "; for (var i = 3; i <= 100; i++) { int3 = int1 + int2; int1 = int2; int2 = int3; sequence += " " + int3 + " " } $("#numbers").append(sequence).show(1000, this.resolve); }).promise(); } function success() { $( "h1" ).text( "Fibonacci!" ); } function failure() { $ ("h1" ).text( "No numbers?" ); } $(function(){ $.when( fib() ).done( success ).fail( failure ); });

20 20 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL So? Although this is a simple example, it illustrates the power of the Deferred pattern. Callbacks in jQuery are a common source of tight coupling. They’re often defined in place, as anonymous functions with too little attention paid to abstraction.

21 21 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Decoupling for fun and profit Without Deferreds, callback logic for animations is tied directly to the animation call as an optional complete argument.

22 22 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Traditionally… function updateStatus() { var $update = $(" "), $statusbar = $("#statusbar"), html = []; // text buffer for ( var i = 0, test = 20; i < test; i++ ) { html.push( " status update "); } html = html.join("\n"); // buffer -> string $update.append(html); $statusbar.append($update); $statusbar.slideDown(5000, function() { console.log("animation is done! On to the next operation"); }); } $(function(){ updateStatus(); });

23 23 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Decoupling for fun and profit Though there’s a simple console.log in the complete argument in this example, far more complicated application data is commonly packed into similar complete callbacks. o This might be acceptable if updateStatus will only ever be used with the anonymous callback function. Alternatively, to solve this, you could add a callback function as an argument to updateStatus, but using Deferred and returning a resolved promise is far more flexible. The following code sample shows how updateStatus could be rewritten to leverage Deferreds:

24 24 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Rewritten Using Deferred function updateStatus() { return $.Deferred(function() { var $update = $(" "), $statusbar = $("#statusbar"), html = []; // text buffer for ( var i = 0, test = 20; i < test; i++ ) { html.push( " status update "); } html = html.join("\n"); // buffer -> string $update.append(html); $statusbar.append($update); $statusbar.slideDown(1000, this.resolve); }).promise() }

25 25 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Decoupling for fun and profit With just the simple application of a Deferred, updateStatus is now much more flexible. o Instead of being tied to a single callback, you can now use that same piece of code in several different flows. The following example contains three callback functions. o The first is equivalent to the original anonymous function in the original example. o The second, alternativeCallback, represents a different path to follow after the animation completes. If the same animation is running on a second page, a different piece of markup will have to be updated. o The third, happyBirthday, represents a function to be called in a special case where a specific UI update would be required, a “HAPPY BIRTHDAY” message indicator, for example. o Three uses of $.when follow. The first replicates the original case with a single callback function. The second shows the alternative callback. The third shows multiple callbacks.

26 26 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Profit! function callback(){ console.log("The animation is done. On to the next operation"); } function alternativeCallback(){ console.log("The animation is done. Let's follow a different path."); } function specialCase(){ console.log("This is a special case. Let's do a special UI update."); } $.when( updateStatus() ).done( callback ); //an alternative callback $.when( updateStatus() ).done( alternativeCallback ); //multiple callbacks $.when( updateStatus() ).done( [ callback, specialCase ] );

27 27 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Decoupling for fun and profit As you can see, the code nicely decoupled the callback logic from the animation buried in the function body. No one even needs to read updateStatus to know how the application flows. It’s all laid out in (nearly) plain English.

28 28 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Deferred.then, Syntactic Sugar for Deferred.fail() and Deferred.done As with aliases for $.ajax like $.get and $.post, jQuery provides a convenient alias for the core Deferred objects: Deferred.then. Deferred.then accepts two arguments, one for resolved promises and the other for rejected promises. Like the functions it maps to, Deferred.done and Deferred.fail, the arguments for Deferred.then can either be individual functions or an array of functions.

29 29 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL $.Deferred.then() function fib() { return $.Deferred(function() { var int1 = 0, int2 = 1, int3, sequence = " 0 1 "; for (var i = 3; i <= 100; i++) { int3 = int1 + int2; int1 = int2; int2 = int3; sequence += " " + int3 + " " } $("#numbers").append(sequence).show(1000, this.resolve); }).promise(); } function success() { $( "h1" ).text( "Fibonacci!" ); } function failure() { $ ("h1" ).text( "No numbers?" ); } $(function(){ $.when( fib() ).then( success, failure ); });

30 30 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Using the Deferred Aspects of $.ajax As was previously mentioned, $.ajax is a Deferred object the success, error, and complete callback methods are analogous to Deferred.done, Deferred.fail, and Deferred.always

31 31 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL A typical ajax request $.get("/status/json/", function( data ) { var $update = $( " " ), $statusbar = $( "#statusbar" ), html = "", statusMessages = data.statusMessages; for ( var i = 0, test = statusMessages.length; i < test; i++ ) { html += " " + status[i] + " "; } $update.append(html); $statusbar.append($update); $statusbar.slideDown(1000); } );

32 32 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Using the Deferred Aspects of $.ajax Let’s leverage Deferred the arguments passed to updateStatus are the same that would be passed to the callback function of a typical Ajax request. o the data, o a text string indicating request status o the jQuery XMLHttpRequest, (jqXHR) object an enhanced version of the standard XMLHttpRequest object.

33 33 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL A Deferred ajax request function getStatus() { return $.ajax({ url : "/status/json/", dataType : “json” }) } function updateStatus( data ) { var $update = $( " " ), $statusbar = $( "#statusbar" ), html = "", statusMessages = data.statusMessages; for ( var i = 0, test = statusMessages.length; i < test; i++ ) { html += " " + statusMessages[i] + " "; } $update.append( html ); $statusbar.append( $update ); $statusbar.slideDown( 1000 ); } $.when( getStatus() ).done( updateStatus );

34 34 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Using the Deferred Aspects of $.ajax note that once again the callback logic is decoupled from a single Ajax request getStatus function becomes more flexible multiple $.ajax requests can be passed into $.when multiple callbacks can be chained

35 35 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL An exaggerated Defered ajax request $.when( $.post("/echo/json", function() { console.log("1") } ), $.post("/echo/json", function() { console.log("2") } ), $.post("/echo/json", function() { console.log("3") } ) ).then([ function() { console.log("4") }, function() { console.log("5") }, function() { console.log("6") } ]).then([ [snipped!]

36 36 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL An exaggerated Defered ajax request […] function() { console.log("7") }, function() { console.log("8") }, function() { console.log("9")} ]).then([ function() { console.log("10") }, function() { console.log("11") }, function() { console.log("12")} ]).done( function() { console.log("Electric Company!") } );

37 37 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Execute a Function No Matter What the Promise Resolution Is with Deferred.always Oftentimes you want a function to be called no matter what the promise resolution is. use Deferred.always (this is just like the complete callback) The following code shows a simplified example that changes the “last updated” indicator in a mail application.

38 38 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Always! $.when( $.ajax( "/get/mail/" ) ).done( newMessages, updateMessageList, updateUnreadIndicator ).fail( noMessages ).always( function() { var date = new Date(); $( "#lastUpdated" ).html( " Folder Updated : " + date.toDateString() + " at " + date.toTimeString() ); } );

39 39 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Chaining and Filtering Deferreds with Deferred.pipe Deferred.pipe, introduced in jQuery 1.6, provides a method to filter and further chain Deferreds. The following code shows a simplified example that uses a chained animation used to manage the build out of the components of a web application. Once the animation queue is complete, the promise is automatically resolved and the done method is fired.

40 40 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Deferred.pipe function buildpage() { return $.Deferred(function( dfd ) { dfd.pipe(function() { return $( 'header' ).fadeIn(); }).pipe(function() { return $( '#main' ).fadeIn(); }).pipe(function() { return $( 'footer' ).fadeIn(); }) }).resolve(); } $.when( buildpage() ).done(function() { console.log(‘done’) } );

41 41 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Filtering Deferreds with Deferred.pipe Deferred.pipe can filter Deferreds based on secondary criteria. Deferred.pipe accepts three arguments: a doneFilter, a failFilter, and a progressFilter Typical use case is a service that returns 200 with an empty result set. It will never get to the error callback.

42 42 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Deferred.pipe $.when( $.ajax( "/get/mail/" ) ).pipe( function( data ) { if ( data.messages.length > 0 ) { return data } else { return $.Deferred().reject(); } ).done( newMessages, updateMessageList, updateUnreadIndicator ).fail( noMessages ).always( function() { var date = new Date(); $("#lastUpdated").html(" Folder Updated : " + date.toDateString() + " at " + date.toTimeString() ); } );

43 43 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Resolving and Rejecting Promises You occasionally need to manually resolve or reject promises. o Deferred.resolve and Deferred.reject. o optional args argument passed to the Deferred.done or Deferred.fail methods depending on the resolution of the promise The following example shows a simplified illustration of these optional arguments. Returning to the mail example, the code snippet creates an updated date string to represent the time of the mail update. This string is passed along to the Deferred.fail and Deferred.done methods. Additionally, the number of messages is passed to Deferred.done to update the #message paragraph with the current number of new messages retrieved.

44 44 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Reject and Resolve Manually function newMessages( obj ) { $( "#message" ).text("you updated at " + obj.date + " and have " + obj.number + " new messages" ) } function noMessages( obj ) { $( "#message" ).text("you updated at " + obj.date + " and have no new messages" ) } $.when( $.ajax( "/get/mail/" ) ).pipe( function( data ) { var date = new Date(); date = date.toDateString() + " at " + date.toTimeString(); if ( data.messages.length > 0 ) { return $.Deferred().resolve({ date: date, number: data.messages.length }); } else { return $.Deferred().reject({ date: date }); } ).done( newMessages ).fail( noMessages );

45 45 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Tracking Progress with Deferred.progress and Deferred.notify Added in jQuery 1.7, the Deferred.progress and Deferred.notify methods combine to allow for in- process updating of long-running functions. At different points in your application, you set notify methods Deferred.notify accepts an optional argument, which will be passed along to the Deferred.progress callback. The Deferred.progress callback method is added to the chain. This callback method should be designed to handle whatever message was sent along via Deferred.notify In the simple example that follows, the function longRunning is a Deferred that uses setTimeout to take 5000ms to resolve its promise. Before the timer is started, there’s a string notification sent out. The progress function accepts that argument and inserts the update text into the DOM. After the process is finished, you notify again that the process is complete and then manually resolve the promise. In theory, the text update could have been handled by the Deferred.done callback, leaving the progress callback to handle just the original notification. There’s just a nice symmetry to using Deferred.notify at both ends of the process. Also, there’s always a case to be made for keeping repetition of code down to a minimum. So it just makes sense to keep all of the notification bound to the progress method.

46 46 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Progress and Notify var longRunning = function() { return $.Deferred(function(dfd) { dfd.notify( "operation started" ) var callback = function() { dfd.notify( "operation finished" ); dfd.resolve(); } setTimeout( callback, 5000 ); }).promise(); longRunning().progress( function( notification ) { $( "#notifier" ).text( notification ).fadeIn( 500 ); }).done(function() { $( "#notifier" ).css({ "color" : "green", "font-weight" : "bold" }) });

47 47 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Debugging with Deferred.state If you ever find the need to debug Deferred resolution (and you will if you ever get deep into using Deferreds), you’ll be taking advantage of Deferred.state. A simple utility function, Deferred.state returns a string value representing the current state of a Deferred. The three return values are “pending,” “resolved,” and “rejected.”

48 48 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Deferred.state var longRunning = function() { return $.Deferred(function( dfd ) { dfd.notify( "operation started" ); console.log( dfd.state ); var callback = function() { dfd.notify( "operation finished" ); dfd.resolve(); } setTimeout( callback, 5000 ); }).promise(); } longRunning().progress( function( notification ) { console.log( dfd.state ); $( "#notifier" ).text( notification ).fadeIn(500); }).done(function() { console.log( dfd.state ); $( "#notifier" ).css({ "color" : "green", "font-weight" : "bold" }) });

49 49 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL The new event API Clearing up a big, confusing mess

50 50 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL JQuery’s New Event API Starting with version 1.7 jQuery has made an effort to simplify the API for setting events. While you’ll still be able to.bind() and.unbind(),.live() and.die() and set.click() and.blur() the old way, there’s now a unified API which bundles all the various functionalities under one, consistent API. The two new methods are.on() and.off(). Moving forward these two new methods represent the preferred API The beauty of.on() is that it replaces the functionality of all the existing event methods with a single, flexible API The following code sample shows a basic example of.on(), using it to bind a click event to an element already present in the DOM. o This would compare to directly using.bind(“click”) or.click()

51 51 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Basic $.on() $(function(){ $("#aDiv").on('click', function(){ console.log("Handler 1"); }); $("#aDiv").on('click', function(){ console.log("Handler 2"); }); Press Me

52 52 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL JQuery’s New Event API Beyond that basic example, on() also exposes the same functionality present in.delegate() and.live() and does so with the exact same syntax as the basic on() example. To use.on() like delegate() or.live(), simply add a second, optional selector argument representing the target element for the event. Here on() is used to listen for clicks on the document and fire the provided handler function if the click originates from an element with the id #anchor. Since the listener is set on the document, it will work whenever and wherever the #anchor appears.

53 53 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL $.on() as $.live() $(function(){ // element doesn’t exist yet, but // we can create a handler anyways $(document).on("click", "#anchor", function(event){ console.log("I have a handler"); }); $("body").append(" Anchor ") });

54 54 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL JQuery’s New Event API Using on() like delegate() uses the exact same syntax as the live() replacement in the previous example. This illustrates one of the benefits of the new, simplified events API. o Instead of remembering two separate methods and their associated arguments, you simply remember the one on() method and adjust your arguments accordingly. o If you truly need to bind events to generic elements across the whole page, you just use.on() on the document and pass in your generic p or a selector. o If, you want to follow the more performant delegate pattern, you simply apply.on() to a more focused selector

55 55 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL $.on() as $.delegate() $(function(){ $("#delegate").on("click", "p", function(){ console.log('ouch'); }).css("color", "green"); }); Hit Me!

56 56 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL JQuery’s New Event API Removing events is as simple as reversing the process with.off(), the same way you would use.unbind() or.die() The following code shows how to remove the events set in the previous examples. $( "#delegate“ ).off( "click", "p“ ); $( document ).off( "click", "#anchor“ ); $( "#aDiv“ ).off( 'click‘ );

57 57 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL JQuery’s New Event API As you can see, this new event API radically simplifies the way jQuery handles events. All the same power and convenience is still available, it’s just presented in a more straightforward, consistent manner.

58 58 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL One more thing

59 59 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Open Source Stuff I work on some open source projects. You can o https://github.com/h5bp/html5-boilerplate https://github.com/h5bp/html5-boilerplate o Build Scripts o https://github.com/h5bp/ant-build-script https://github.com/h5bp/ant-build-script o https://github.com/h5bp/node-build-script (using grunt, more local flavor) https://github.com/h5bp/node-build-script o https://github.com/h5bp/rake-build-script o https://github.com/roblarsen/CanvasJS https://github.com/roblarsen/CanvasJS

60 60 © COPYRIGHT 2012 SAPIENT CORPORATION | CONFIDENTIAL Bio Rob Larsen github: HTML + CSS + JavaScript Come Work With Me:

61 61 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Thank You!


Download ppt "JQuery: New Features and APIs 4-25-2012. 2 © COPYRIGHT 2011 SAPIENT CORPORATION | CONFIDENTIAL Contents Introduction Deferred The New Event API."

Similar presentations


Ads by Google