Bug Tracker

Opened 7 years ago

Closed 7 years ago

Last modified 7 years ago

#11894 closed bug (invalid)

Deferred.notify does not pass expected messages

Reported by: mankyd@… 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"]

Change History (3)

comment:1 Changed 7 years ago by mankyd@…

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

http://jsfiddle.net/3duVe/

comment:2 Changed 7 years ago by jaubourg

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?

Last edited 7 years ago by jaubourg (previous) (diff)

comment:3 Changed 7 years ago by anonymous

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!

Note: See TracTickets for help on using tickets.