1

So as below code, it only deal with the ajax call success case, if the ajax call failed, it is ignored and the deferred.reject() will never be invoked. So if we meet the failed case, will there any event listener inside jQuery will be keep forever to cause memory leak?

$.when(loadSomething).done(function() {
    // ...
});

function loadSomething() {
    var deferred = $.Deferred();

    // Only deal with the success case,
    // If the ajax call failed, it is ignored and the deferred.reject() will never be invoked.
    // So if we meet the failed case, will there any event listener inside jQuery will be keeped 
    // forever?
    ajaxCallToLoad(onResult);

    function onResult() {
        deferred.resolve();
    }

    return deferred.promise();
}
Crusoe.Xia
  • 27
  • 3
  • 1
    In case you're simply doing an ajax call, `$.ajax`/`$.post`/`$.get`/`$.getJSON` return a jqXHR object which is compatible with the Deferred methods and is automatically resolved for you. So you could return that object from `ajaxCallToLoad` instead of creating another deferred. – Fabrício Matté Dec 19 '13 at 03:49
  • Thanks, there is reason I cannot control the behavior of `ajaxCallToLoad`. And do you mean If I created a deferred object, I should always may sure the resolved or reject is invoked later? And that could cause memory leaks? I have tried to read Jquery's source code, but it is really complicate... – Crusoe.Xia Dec 19 '13 at 04:14
  • Whether it would cause memory leaks depends on the Deferred implementation, but yes it's good practice to always resolve or reject it. – Fabrício Matté Dec 19 '13 at 05:04

2 Answers2

0

To answer your real question, you will only leak memory if you're maintaining a reference to the deferred and/or promise somewhere in your code despite whether or not you resolve or reject the deferred. If there are no references, then it'll be garbage collected like normal.

That said, I think that in this case rather than manually constructing a Deferred, you should be using the .then method allows you to transform/filter the results. For the sake of this example, lets create a method called load which is just randomly resolves or rejects a deferred, analogous to an ajax request that can potentially fail.

function load() {
    return $.Deferred(function( dfr ) {
       if ( Date.now() % 2 ) {
          dfr.resolve( 1 );
       }
       else {
          dfr.reject( "OHNO!" );
       }
    }).promise();
}

What you're now able to to is use .then to filter it like so:

var filteredResult = load().then(function( result ) {
    return result * 2;
});

filteredResult is now a promise where if load was resolved, it doubles the original result, so filterResult.done( console.log.bind( console ) ) would print 2 to the console. If the load had failed/been rejected, then the failure handlers would still work appropriately.

dherman
  • 2,832
  • 20
  • 23
0

So if we meet the failed case, will there any event listener inside jQuery will be keep forever to cause memory leak?

Almost certainly not.

But if you do that, you're explicitly using promise semantics but then breaking the promise contract. That's poor practice. You have to "best practices" options:

  1. Continue using promises, but stick to the contract. Update ajaxCallToLoad so that it also notifies you of failure, and call reject on your deferred when that happens. (If ajaxCallToLoad is using jQuery's $.ajax function, you could just use the jqXHR object that $.ajax returns; it implements Promise.)

  2. If you don't want to fulfill the promise contract, just use a normal "success" callback rather than a promise.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks for your replay, I did some testing, put `$.when($.Deferred()).done(function() {})` into a loop, and check the chrome task manager of the memory it use, it goes up and down around 96MB. Looks like the garbage collection works for it. Your answer proved it, thanks – Crusoe.Xia Dec 19 '13 at 08:42