Monday 5 January 2015

JQuery Deferred and Promises

Why promises?

Synchronous operations guarantee some maintenance easiness to code. But in the world of asynchronous operations, callbacks are the disguised maintenance monsters waiting for their turn. It is quite easy to get lost in a series of async operations and its callbacks. Attaching callbacks to async operations and invoking other async operations in callbacks can be equated to the future chaos. The Deferred and the Promises help us face such scenarios in a semantically justifying way

The trivial promise pun

We tend to give promises to fill the gap of possible insecurity over some matter. jQuery promises are nothing different in its purpose.

I  went to a food court last evening and ordered a yummy dinner at the South Indian Counter. The guy who took my order gave an “alarm disc” (Don’t know the exact name for fancy disco light disc which alarms when the food is ready at the counter)

With the disc, I went to wash my hands, I texted my friend, checked out the latest feed updates in Facebook and engaged in blabber with the friends who accompanied me, all quite peacefully - Just because I had a promise for the dinner with me  - the alarm disc!

There are two point of contacts now, that can let me know about the ordered dinner; One the promise given from counter and the other the counter itself.

Hence, after waiting for a while I walked into the counter to know the baking status of my dinner.It was still being baked. A few minutes passed. Suddenly, in an unknown moment the alarm rang and I grabbed my dinner from the counter. This is quite normal.

Deferred can give a promise

Deferred is analogous to the counter which initiated the baking of my dinner, an asynchronous operation that takes some time. Thus Deferred represents an operation that will be completed in future. I can get a promise from the Deferred. The promise let me know exactly when the result of that asynchronous operation is ready. Analogous to the counter, the Deferred itself can also notify regarding same.

After all, Deferred can actually change the status of async operation to the resolved state after successful completion of the process or to the failed state on failure, specifically only once. In other words, deferred has the privilege to decide that the operation is a success or failure, depending on the situation.
The promise object allows listening to an async operation – just like I stayed tune to the table alarm disc. While promise allows state inspection, it is always immutable.

Deferred potentially can be the state changing private area of the application that performs  an asynchronous operation, while promise is the public handle or component of the Deferred that can be passed among the application modules that are interested in the state changes. In effect, this decouples the actual operation from its consumers.

Following are the state changing methods of the Deferred.
  • resolve
  • resolveWith
  • reject 
  • rejectWith
Following are the methods of the Deferred, that represent events to which callbacks can be added. This also corresponds to methods of a promise interface.
  • done
  • fail
  • then

Deferred - Official definition

A constructor function that returns a chainable utility object with methods to register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function.
The below example might explain the above definition better. Line 1 invokes the constructor function. Deferred begins with the pending state.
var deferred = $.Deferred();
deferred.always(function() {
}).done(function() {
}).fail(function() {
}).then(function(){
});
All the callbacks added above are queued for execution on state changes. deferred.resolve() or deferred.reject() triggers state changes and also the execution of associated callbacks. “then” callbacks are triggered for both resolved and rejected deferred promises.

Handling callbacks blissfully

Jquery ajax method provided means to attach the success and error handling callbacks to it. Since Jquery 1.5 asynchronous processes such as AJAX returns jqXhr object which implements promise interface or otherwise it “is a” promise. As of Jquery 1.8, using success, error and complete handlers in AJAX is deprecated. It is recommended to use
$.ajax().done(function() {
}).fail(function() {
});

Jquery animation is yet another asynchronous operation which returns a promise. Before Jquery 1.8 to attach a callback after animation is completed
$(“#container”).animate({
height: 100px;
}, 5000, function() {
    //callback to be executed after animation
});
Since 1.8 as the animate returns a promise
$(“#container”).animate({
height: 100px;
}, 5000).
done(function() {
    //callback to be executed after animation
});
It is good to know that when an element or a collection of elements undergo animation, a Deferred object would be assigned to the data attribute. Here the promise can be returned from the DOM element/collection which will be listened for completion of all animation on the corresponding element/collection.
$( "div" ).each(function( i ) {
$( this ).fadeIn().fadeOut( 1000 * ( i + 1 ) );
});
$( "div" ).promise().done(function() {
console.log( "Finished all animations on div collection!" );
});

The nifty when

$.when can accept a set of Deferred objects. The when method returns a promise from a new master deferred object which keeps track of each individual deferred object passed. Master deferred object will be resolved if all the individual deferred objects are resolved and rejected when atleast one of the deferred objects is rejected. Following example from Jquery website throws light into the usage.
var d1 = new $.Deferred();
var d2 = new $.Deferred();
var d3 = new $.Deferred();
$.when( d1, d2, d3 ).done(function ( v1, v2, v3 ) {
    console.log( v1 ); // v1 is undefined
    console.log( v2 ); // v2 is "abc"
    console.log( v3 ); // v3 is an array [ 1, 2, 3, 4, 5 ]
});
d1.resolve();
d2.resolve( "abc" );
d3.resolve( 1, 2, 3, 4, 5 );

The fail callback associated with when can serve as an area to perform some cleaning up for the requests already in progress that became invalid due to the fact that some other operation in the queue has failed.
• • •

Friday 2 January 2015

jQuery events - direct and delegated events

Historically Jack bound many events to buttons, forms, links and text boxes since he started working with jQuery. He has even played with event propagation and fixed some curious issues by using stopPropagation() method. But this is for the first time that an event he bound to a simple link just didn't work. There were no silly syntax errors.
See the code snippet that Jack wrote.
$(".sub-heading").click(function() {
    $(this).css({"background-color": "yellow"});
});

Turning point
Jim has committed code which loaded some html content with the same "sub-heading" class via AJAX. Highlighting on click was not working for only those subheadings.
Jack felt a little relaxed, but dwelling more he understood that Jim is not the culprit! Jim has correctly loaded the content which had the elements with the same class name "sub-heading" via AJAX. Something related to events was not working as expected for the dynamically loaded content.

Event revelations

The facts Jack learnt regarding JQuery events has totally changed the way he approached events in jQuery.

There are two types of jQuery events
  1. Direct or directly bound events
  2. Delegated events

1. Direct or directly bound events

The event Jack created was indeed a direct event. The known fact regarding these events before was that "it works usually..".
Following are the other facts revealed.
- Every element matching the selector has a copy of the handler and it is triggered upon the event.
- The event is propagated till the document up in the hierarchy, for those elements having a matching the selector as bound in the event.
- If the event binding is done on document ready, only those elements matching the selector present when document is ready will be bound. Those elements created dynamically won't be bound.

Jack's Fixing instinct

Jack understood the issue. The first idea that hit his mind was to attach the handler as soon as Jim dynamically loaded the content. He even searched for the success handler of Jim's AJAX call. But, he was just curious about the other type of jQuery event and thought to peep into that as well.

2. Delegated events

Learning delegated events, Jack was surprised to knowing that it was the most suitable one for the situation. Here is why.
  • It is bound to a container having the the target elements that should respond to the event.
  • One and only one handler is shared by all the the target elements.
  • It works for future elements or elements that are dynamically loaded.
  • The event is propagated and triggered for elements with matching selector found from the inner most element to those up in hierarchy in the container. Otherwise it won't be fired for matching elements not inside the bound container.
This is how Jack refactored his code after observing that all the present and future subheadings are loaded into the "div#container"
$("#container").on("click", ".sub-heading", function() {
    $(this).css({"background-color": "yellow"});
});

The on handler

Earlier JQuery used live, bind, delegate etc for dealing with different event handling usecases. As of JQuery 1.7 the "on" handler includes all those scenarios and these methods are deprecated. Here is the basic syntax.

$("{container}").on("{event}", "{selector}", function() {
    
});

"on" method can be used to attach delegated events. But it can also be used to attach direct events. Omitting the "selector" argument or specifying it as null, the handler is bound directly. See below.

$(".sub-heading").on("click", function() {
    $(this).css({"background-color": "yellow"});
});

If there are events bound to a set of elements, delegated event is the way to go. Suppose there is an html table with one thousands rows, isn't it smart to bind the event to the table than to each of the thousand rows?

Doing it once using one

Jack also learnt that he can use "one" instead of on to trigger event only once for the matched selector.

Switching it off

The events attached using "on" can be removed using "off".
• • •

Thursday 27 November 2014

Mongoose default current timestamp in Schema

There are cases when you would like Mongoose to implicitly add the current timestamp to an "updatedAt" field.

Mongoose API documentation has an example of the same which uses Date.now as the default parameter.
Eg:
var Schema = require('mongoose').Schema;
var mySchema = new Schema({
   title: {
     type: String
   },
   updatedAt: {
     type : Date,
     default : Date.now
   }
});
But chances are there for someone to replace Date.now with the often interchangeably used new Date() expression in JavaScript. Ah! at least I did this in one of the schema definitions which brought unexpected results. Such errors are difficult to catch during the early stages and might stay hidden in the background for a while, until someone somewhere gets a heavy surprise out of it.

For those who aren't clear about the difference both statements make in the above context of default value specification:-
Using new Date() constructor
It is executed only once when the server starts up and the Mongoose Schema are loaded. All the subsequent calls to get the default value, will get the same historic date value when the schema was initialised.
Using Date.now method
We can be sure that whenever it is invoked we get current timestamp as expected.
• • •