how does jquery's promise method really work?

robx picture robx · May 21, 2011 · Viewed 41.2k times · Source

I don't really understand what delegate and promise are.

According to the docs -

  • delegate would bind a selector and event to some sort of wrapping container that can be used again at a later time for current and future items.
  • promise() would remap things back to when it was first bounded if everything newly loaded matches. Maybe I don't really understand this promise method.

What if the wrapper is still there, but the contents in the wrapper container have changed, and/or reloaded via Ajax? Why is it that the events are not triggering or working as it would the first time it is bound?

And yes, I have been to the docs page, I just don't understand their explanations completely.

Answer

lonesomeday picture lonesomeday · Jun 4, 2011

I'm a bit confused by this question. I think this is because you are confused by promise and delegate. They are in fact completely unrelated features of jQuery. I'll explain each separately:

delegate

delegate is a feature of jQuery that was introduced in jQuery 1.4.2. (It is a nicer approach to the live feature that was added in jQuery 1.3). It solves a particular problem that comes with modifying the DOM, and particularly with AJAX calls.

When you bind an event handler, you bind it to a selection. So you might do $('.special').click(fn) to bind an event handler to all the members of the special class. You bind to those elements, so if you then remove the class from one of those elements, the event will still be triggered. Inversely, if you add the class to an element (or add a new element into the DOM), it won't have the event bound.

There is a feature of Javascript that mitigates this called "event bubbling". When an event is triggered, first the browser notifies the element where the event originated. Then it goes up the DOM tree, and notifies each ancestor element. This means that you can bind an event handler on an element high up the DOM tree, and events triggered on any child elements (even those that don't exist when the handler was bound).

delegate is jQuery's implementation of this. First, you select a parent element. Then you specify a selector – the handler will only be run if the originating element matches this selector. Then you specify an event type, such as click, submit, keydown, just as with bind. Then finally you specify the event handler.

$('#containingElement').delegate('a.special', 'click', function() {
    alert('This will happen on all links with the special class');
});

promise

promise is another relatively recent addition to the jQuery featureset. It is part of the Deferred concept that was introduced in jQuery 1.5. (I think the similarity in sound between "deferred" and "delegate" is probably the source of confusion.) This is a way of abstracting away the complications of asynchronous code. The best example of this is with AJAX calls, as the object returned by $.ajax is a Deferred object. For instance:

$.ajax({
    url: 'somepage.cgi',
    data: {foo: 'bar'}
}).done(function() {
    // this will be run when the AJAX request succeeds
}).fail(function() {
    // this will be run when the AJAX request fails
}).always(function() {
    // this will be run when the AJAX request is complete, whether it fails or succeeds
}).done(function() {
    // this will also be run when the AJAX request succeeds
});

So it is in many ways the same as binding success handlers in the $.ajax call, except that you can bind more than one handler, and you can bind them after the initial call.

Another time when it would be useful to deal asynchronously is with animations. You can provide callbacks to functions, but it would be nicer to do this with similar syntax to the AJAX example I've provided above.

In jQuery 1.6, this functionality was made possible, and promise is part of this implementation. You call promise on a jQuery selection, and you'll get an object that you can bind event handlers to, when all the animations in the object have completed.

For instance:

$('div.special').fadeIn(5000).promise().then(function() {
    // run when the animation succeeds
}).then(function() {
    // also run when the animation succeeds
});

Again, this is similar in effect to traditional methods, but it adds flexibility. You can bind the handlers later, and you can bind more than one.

Summary

Basically, there is no significant relationship between delegate and promise, but they're both useful features in modern jQuery.