Question

We have this anonymous function in our code, which is part of the jQuery's Ajax object parameters and which uses some variables from the function it is called from.

this.invoke = function(method, data, callback, error, bare) {
      $.ajax({
        success: function(res) {
            if (!callback) return;

            var result = "";
            if (res != null && res.length != 0)
                var result = JSON2.parse(res);

            if (bare)
            { callback(result); return; }

            for (var property in result) {
                callback(result[property]);
                break;
            }
        }
   });
}

I have omitted the extra code, but you get the idea. The code works perfectly fine, but it leaks 4 Kbs on each call in IE, so I want to refactor it to turn the anonymous function into a named one, like this.onSuccess = function(res) { .. }.

The problem is that this function uses variables from this.invoke(..), so I cannot just take it outside of its body. How do I correctly refactor this code, so that it does not use anonymous functions and parent function variables?

Update. I am thinking of creating a separate object, initializing it with the same parameters, and pass its onSuccess function as a parameter for jQuery's Ajax object. Although I suspect that it will still leak memory.

Update 2. I have found a few links suggesting that the actual leak might be caused by jQuery. Simple jQuery Ajax call leaks memory in Internet Explorer Memory leak involving jQuery Ajax requests

Still it was good to find a way to refactor this.

Update 3. I will wait for a more generic solution, before accepting an answer.

Was it helpful?

Solution

You can add extra params to the ajax request that can be accessed in the success callback:

this.invoke = function(method, data, callback, error, bare) {
    $.ajax({
        success: onSuccess,
        invokedata: {
         callback: callback,
         bare: bare
        }
    });
};

var onSuccess = function(res) {
    var callback = this.invokedata.callback,
        bare = this.invokedata.bare;
    if (!callback) return;

    var result = "";
    if (res != null && res.length != 0)
        var result = JSON2.parse(res);

    if (bare){
        callback(result); 
        return;
    }

    for (var property in result) {
        callback(result[property]);
        break;
    }
}

OTHER TIPS

+1 for excellent, excellent question - I feel your pain - this is really nicely factored as it is.

One suggestion (and maybe this is what you meant by your update)...define a wrapper for onSuccess and make it return the function you want to assign. Then call the outer function and assign it to the "success" option, passing the values it needs. Those values will be pre-assigned to the variables in the inner function. Not actually sure if this will help - you still end up with an anonymous function - but worth a try

this.invoke = function(method, data, callback, error, bare) {
    $.ajax({
        success: onSuccess(callback, bare);
    });
};

var onSuccess = function(callback, bare) {
     return function() {
        if (!callback) return;

        var result = "";
        if (res != null && res.length != 0)
            var result = JSON2.parse(res);

        if (bare)
        { callback(result); return; }

        for (var property in result) {
            callback(result[property]);
            break;
        }
     }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow