Skip to main content

Bug Tracker

Side navigation

#11894 closed bug (invalid)

Opened June 12, 2012 03:38AM UTC

Closed June 12, 2012 11:01AM UTC

Last modified June 12, 2012 11:56AM UTC

Deferred.notify does not pass expected messages

Reported by: mankyd@gmail.com Owned by:
Priority: undecided Milestone: None
Component: unfiled Version: 1.7.2
Keywords: Cc:
Blocked by: Blocking:
Description

I was writing a preloader for a project I was working on. The project has a set of slides that it needs to load content for. When each slide starts its preloading, it is supposed to notify up the chain that it is starting, then notify again that it is finishing, before finally resolving the deferred. What I have noticed is that while the first two calls to notify work as expected, subsequent calls do not. Instead, they simply repeat the second call over. This is best demonstrated by example.

Expected output of the following code:

slide_loading
slide_loaded
slide_loading
slide_loaded
slide_loading
slide_loaded

Actual output:

slide_loading
slide_loaded
slide_loaded
slide_loaded
slide_loaded
slide_loaded

Code:

function Slide() {
    this.preload = function() {
        var preload_deferred = new $.Deferred();
        setTimeout(function() {
            preload_deferred.notify('slide_loading');
            preload_deferred.notify('slide_loaded');
            preload_deferred.resolve();
        }, 1000);
        return preload_deferred.promise();
    };
}
var slides = [new Slide(), new Slide(), new Slide()];
var d = [];
for (var i = 0; i < slides.length; i++) {
    d.push(slides[i].preload());
}
var w = $.when.apply(null, d);
w.progress(function(msg) { console.log(msg);});

If you replace the last line with:

w.progress(function() { console.log(arguments);});

You actually get something like the following out:

["slide_loading", undefined, undefined]
["slide_loaded", undefined, undefined]
["slide_loaded", "slide_loading", undefined]
["slide_loaded", "slide_loaded", undefined]
["slide_loaded", "slide_loaded", "slide_loading"]
["slide_loaded", "slide_loaded", "slide_loaded"]
Attachments (0)
Change History (3)

Changed June 12, 2012 04:38AM UTC by mankyd@gmail.com comment:1

I realize that a jsFiddle demonstrating all of this would be nice:

http://jsfiddle.net/3duVe/

Changed June 12, 2012 11:01AM UTC by jaubourg comment:2

_comment0: That's not how notification works: only the latest progress value is kept "in memory" since the Deferred already progressed to that point. \ \ Once your preload has reached the slide_loaded progress state and it is resolved, then the Deferred will never ever get back to the slide_loading state: it will stay in its current state indefinitely. \ \ To understand why, just mentally replace slide_loading and slide_loading with "0%" and "100%". Once "100%" is reached, it doesn't make sense to go back to "0%", does it? \ \ How did you expect notify/progress to work?1339498915415039
resolution: → invalid
status: newclosed

That's not how notification works: only the latest progress value is kept "in memory" since the Deferred already progressed to that point.

Once your preload has reached the slide_loaded progress state and it is resolved, then the Deferred will never ever get back to the slide_loading state: it will stay in its current state indefinitely.

To understand why, just mentally replace slide_loading and slide_loaded with "0%" and "100%". Once "100%" is reached, it doesn't make sense to go back to "0%", does it?

How did you expect notify/progress to work?

Changed June 12, 2012 11:56AM UTC by anonymous comment:3

Hmm. My parent deferred is composed of multiple "child" deferreds that are unaware of each other. I was expecting each child to be able to report there progress individually, and have the parent be able to aggregate that information itself. Thus each child could report that they started the loading process and then, later, report that they finished the loading process.

BUT, I just realized something that makes this a moot point. What is actually being reported to the callback, via the arguments variable, is an array of the statuses. Thus if there is 1 child, one message will be passed back. If there are 20 children, 20 messages will be passed back. This is stated, sort of, in the documentation: "If the master Deferred is resolved, it is passed the resolved values of all the Deferreds that were passed to jQuery.when."

It may be worth making this a little clearer by having the documentation make explicit mention of progress in addition to resolved, or by including an example. Thanks!