Why jQuery.proxy rocks my world!

Its been very recent that I’m seriously looking into Javascript – and trust me, there is no dearth of stuff that can be achieved with purely client side code (HTML/CSS/JS). With the modern browsers churning out best of the breed in JS environments (both headed & headless), everything is going to come to a browser near you! Its just a matter of time!

Anyways, on more subtle issues, while writing a purely client side JS app using Backbone.js & jQuery Mobile I came across jQuery.proxy method – something that I’ve really started using almost everywhere.. The method is so useful that sometimes I wonder – why jQuery did not implement it in callback mechanism by default.

A quick overview about the problem…

  1. var FBNotificationWatcher = new JS.Class({
  2.  
  3.   initialize : function(timeout) {
  4.     this.url = "http://foo/return/json";
  5.     this.getNotifications(); // initiate the first fetch
  6.   },
  7.  
  8.   getNotifications : function() {
  9.     $.ajax({
  10.       // do your ajax call
  11.       url : this.url;
  12.       success : this.processNotifications
  13.     });
  14.   },
  15.  
  16.   processNotifications : function(rawNotificationData) {
  17.     // process notifications… AND
  18.     setTimeout(jQuery.proxy(this.getNotifications, this), this.timeout); // start all over again…
  19. });

When a new object of FBNotificationWatcher is created, all goes well. this.getNotifications gets the JSON & this.processNotifications processes it. However, when setTimeout’s occurs and this.getNotifications is called again, the context of “this” is set to the “window” object. And because of this, the code breaks in this.getNotifications method.

Now this is very frustrating – as you just lost the object you were operating within.

Solution? jQuery.proxy comes to rescue!

  1.  processNotifications : function(rawNotificationData) {
  2.     // process notifications…
  3.  
  4.     setTimeout(jQuery.proxy(this.getNotifications, this), this.timeout); // start all over again…
  5.   }

If we setup the setTimeout call like this, jQuery will guarantee that the context of “this” when this.getNotifications gets executed, will always be set to the original FBNotificationWatcher object which had setup the timer. The second argument to jQuery.proxy defines the context you want to get back when the setTimeout callback gets executed.

This concept can be used anywhere you want your callbacks to retain their context.

Read more about the method at jQuery API docs.

Related posts:

  1. Kickass MCV for your Javascript Apps Very recently, I had an opportunity to work on a...
  2. How to commission developer machines in an agile way? During the past year – working at AdoMado, I’ve seen myself...

Related posts brought to you by Yet Another Related Posts Plugin.

  • http://www.frankdenbow.com Frank Denbow

    Cool! I didnt know you could force the context in this way. I too am getting heaving into Javascript (beyond the minor enhancements to sites, but using it as the primary driver of interaction). It is the way to go!

  • http://profiles.google.com/jonathan.pasquier Jonathan Pasquier

    Is there any added benefits upon using a closure?
    For instance,
    var that = this;
    setTimeout(function() { that.getNotifications() }, this.timeout);
    would do the job.

    It’s two lines instead of one, though :-)

  • http://makuchaku.in/ makuchaku

    I’m glad that this post was of any help :)

  • http://makuchaku.in/ makuchaku

    Thanks!
    Will try it out the next time…

  • masklinn

    Two improvements to your current technique:

    * jQuery.proxy(this, ‘getNotifications’) does the same thing as jQuery.proxy(this.getNotifications, this) and is (I find) more readable. Though it’s more liable to typos

    * Since you’re using backbone, you’ve integrated underscore. Underscore provides both _.bind, which does the same thing as the first form of jQuery.proxy (the one you use) but adds the possibility to curry the function (provide additional arguments immediately) and _.bindAll. _.bindAll is not called when setting a callback on an event, it’s called after creating an object (or instance), and it calls _.bind on each method and then re-sets them in place. So in your example you’d just add “_.bindAll“ in the first line of the constructor, and then use “setTimeout(this.getNotifications)“, and you’ll get the right context everywhere.

  • http://www.frankdenbow.com Frank Denbow

    Yep! Reminds me to explore some of the aspects of Jquery that I rarely use. Also to check out Backbone to organize my js a bit better.

  • Jerome Etienne

    what about setTimeout(this.getNotification.bind(this), 42); ?

  • http://makuchaku.in/ makuchaku

    Good point, trying this right away…
    Thanks!

  • http://makuchaku.in/ makuchaku

    Other parts of the app use Backbone.
    FBNotificationWatcher is a simple implementation based on JS.Class (http://jsclass.jcoglan.com/classes.html)

  • http://makuchaku.in/ makuchaku
  • http://www.frankdenbow.com Frank Denbow

    Looks good. Javascript: The Good Parts is on my list as well.

  • Stephen

    This just proves why jQuery is not as great as people make it out to be. PrototypeJS and many other frameworks have had context binding functionality (not to mention variations, like binding as an Event Handler, where the first argument is guaranteed to be the event object, and of course currying) for literally years, and they are much more obvious to use.

    This is just another reason why I think of jQuery as the MS Frontpage of Javascript Libraries.

  • Anonymous

    Wow. Your last sentence is the worst comparison I’ve ever heard. You clearly have no idea what the hell you are talking about.

  • http://twitter.com/Bryant_ Bryant Hughes

    thats how ive always handled it as well