domenica 7 aprile 2013

Decoding jQuery – Callbacks Object

In the Decoding jQuery series, we will break down every single method in jQuery, to study the beauty of the framework, as an appreciation to the collective/creative geniuses behind it.



The jQuery.Callbacks() function, introduced in version 1.7, returns a multi-purpose object that provides a powerful way to manage callback lists. It supports adding, removing, firing, and disabling callbacks. (jQuery API Doc)
It provides many Supported Flags. It is structured as a list of space-separated strings that change how the callback list behaves (eg. $.Callbacks( ‘unique stopOnFalse’ )).
Callbacks Object can also be used to do pub/sub and it is also used to make jQuery.Deferred().
1. Structure of jQuery.Callbacks()
Below is how the structure of jQuery.Callbacks() function looks like in jQuery source(callbacks.js).

jQuery.Callbacks = function( flags ) {
 
  // Convert flags from String-formatted to Object-formatted
  // (we check in cache first)
  flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
 
  var // Actual callback list
    list = [],
    // Stack of fire calls for repeatable lists
    stack = [],
    ...
    // Add one or several callbacks to the list
    add = function( args ) {
      //...
    },
    // Fire callbacks
    fire = function( context, args ) {
      //...
    },
    self = {
      //...
    };
 
  return self;
};
 
add function – adds a list of callbacks to the variable list array.
fire function – loops through the items in the list and fire them one by one.
self object – is the actual Callbacks object returned at the end of the function.
The most important methods in the self object are:
add() adds a callback or a collection of callbacks to the list, this is the one we use to build subscribe in pub/sub function
fireWith() method actually calls all callbacks with the given context and arguments
fire() method inside the self object executes fireWith with the object as the context, this is the one we use to build publish in pub/sub function
There are also many other essential and useful methods in the self object, they are:
has(): a boolean check to find out if a callback list contains a specific callback
remove(): Remove a callback from the list
empty(): a method for emptiying a callback list of all callbacks added so far
disable(): disables further calls being made to the callback list
lock(): lock the list in its current state

2. How to use Callbacks object
Suppose we have a Rails application, assume we have a function displayAlert and msgStatus like the ones below.

var displayAlert = function( msg ) {
      console.log( msg );
    },
    msgStatus = function ( msg ) {
      fn1(msg + '...feed is read!');
      return false;
    },
    callbacks = $.Callbacks();
callbacks.add( displayAlert );
callbacks.fire( 'new message 1' ); // outputs: new message 1
callbacks.add( msgStatus );
callbacks.fire( 'new message 2' ); // outputs: new message 2, new message 2 is read!
 
After creating a callbacks = $.Callbacks();, we can use add to add displayAlert to the callbacks variable as a list item, and later add postFeed as a new item. By using fire, the callbacks object is fired with the function/functions executed.
As explained above, fire is actually fireWith with the object itself as the context, you can also define/specify a context and arguments for callbacks being bound and fired.

var fn = function (argA, argB) {
  //..
}
callbacks.add( fn );
callbacks.fireWith( window, ['foo', 'bar']);
// outputs: foo, bar
 
Addy Osmani provided example code for some of these methods and some of the flags arguments in his Demystifying jQuery 1.7′s $.Callbacks

3. How does a pub/sub function work
Below is an example of building a jQuery.Actions for publish and subscribe when microposts are received/sent, as well as sent status.

var displayAlert = function(msg) {
  //...
}
 
var msgStatus = function(msg) {
  //...
}
var actionItems = {};
 
jQuery.Actions = function( id ) {
  var callbacks,
      method,
      action = id && actionItems[ id ];
  if ( !action ) {
    callbacks = jQuery.Callbacks();
    action = {
      publish: callbacks.fire,
      subscribe: callbacks.add,
      unsubscribe: callbacks.remove
    };
    if ( id ) {
      actionItems[ id ] = action;
    }
  }
  return action;
};
 
// Subscribers
$.Actions('micropostArrived').subscribe(displayAlert);
$.Actions('micropostSent').subscribe(displayAlert);
$.Actions('micropostSent').subscribe(msgStatus);
 
// Publisher
$.Actions('micropostArrived').publish('New Items arrived');
$.Actions('micropostSent').publish('Item posted');
 
In the above example, the publish and subscribe use fire and add for the pub/sub pattern, and remove for unsubscribe.
This is not the only way to use jQuery for pub/sub, Addy’s Four Ways To Do Pub/Sub With jQuery 1.7 and jQuery UI gist discussed more ways of doing it with jQuery and jQuery UI.

Nessun commento:

Posta un commento