Tried $.when and $.then no lucky

删除回忆录丶 提交于 2019-12-25 02:25:33

问题


I am trying to display some words and then when it is complete display the full sentence.

the problem is doesn't matter which I try, it plays all together. Not one after the other.

Can one of you explain to me what I am doing wrong?

function DisplayHdline( callback){
    var str = "HELP STOP CRUELTY NOW.";
    var spans = '<span>' + str.split(/\s+/).join(' </span><span>') + '</span>';

    jQuery(spans).hide().appendTo('#vidheadline').each(function(i) {
        jQuery(this).delay(2000 * i).fadeIn('fast').delay(1000).fadeOut(50);
    });
    callback();
}

function addComplete(){
    jQuery('LOREM IPSUM DOLLOR').appendTo('#vidheadline').fadeIn();
    //alert('Where is my sentence');
}

DisplayHdline(function(){
    jQuery.when( this ).done( addComplete() );
});

//jQuery.when( DisplayHdline() ).then( addComplete() );

Thanks

Ps.: I did search and tried different sollutions found here. But all with the same outcome, so clearly I am doing something wrong

Edit: this is what I ended up with function typePlay(){ var actionStr = "HELP STOP CRUELTY NOW."; var spans = '' + actionStr.split(/\s+/).join(' ') + '';

    function DisplayHdline(){
        return jQuery(spans).hide().appendTo('#vidheadline').each(function(i) {
            jQuery(this).delay(2000 * i).fadeIn('fast').delay(1000).fadeOut(50);
        }).promise();
    }

    function addComplete(){
        jQuery('#vidheadline').hide().append( '<p id="completeHeadline">' +actionStr+'</p>' ).fadeIn();
    }

    DisplayHdline().done(addComplete);

}

    window.setInterval(function typeTimer(){
        jQuery('#vidheadline').empty();
        typePlay();
    }, 25000);

typePlay().done(typeTimer);

Thanks ;)


回答1:


Callbacks and Deferreds are two different techniques for chaining asynchronous actions. You do one, or the other.

$.when doesn't care that DisplayHdLine() accepts a callback; what it expects is that it returns a Deferred (or Promise), and it doesn't.

Using the callback approach, what you want is;

DisplayHdline(addComplete);

However, you then have the problem that you're calling the callback within DisplayHdLine at the wrong place. You need to call it once all of your elements have faded in. The easiest way to do this is using promise();

function DisplayHdline(callback){
    var str = "HELP STOP CRUELTY NOW.";
    var spans = '<span>' + str.split(/\s+/).join(' </span><span>') + '</span>';

    jQuery(spans).hide().appendTo('#vidheadline').each(function(i) {
        jQuery(this).delay(2000 * i).fadeIn('fast').delay(1000).fadeOut(50);
    }).promise().done(callback);
}

You're complete code for this would then be:

function DisplayHdline(callback){
    var str = "HELP STOP CRUELTY NOW.";
    var spans = '<span>' + str.split(/\s+/).join(' </span><span>') + '</span>';

    jQuery(spans).hide().appendTo('#vidheadline').each(function(i) {
        jQuery(this).delay(2000 * i).fadeIn('fast').delay(1000).fadeOut(50);
    }).promise().done(callback);
}

function addComplete(){
    jQuery('LOREM IPSUM DOLLOR').appendTo('#vidheadline').fadeIn();
    //alert('Where is my sentence');
}

DisplayHdline(addComplete);

However, as you're now using deferreds within DisplayHdline, you could return the promise from DisplayHdline, which may give you cleaner code:

function DisplayHdline(){
    var str = "HELP STOP CRUELTY NOW.";
    var spans = '<span>' + str.split(/\s+/).join(' </span><span>') + '</span>';

    return jQuery(spans).hide().appendTo('#vidheadline').each(function(i) {
        jQuery(this).delay(2000 * i).fadeIn('fast').delay(1000).fadeOut(50);
    }).promise();
}

function addComplete(){
    jQuery('LOREM IPSUM DOLLOR').appendTo('#vidheadline').fadeIn();
    //alert('Where is my sentence');
}

DisplayHdline().done(addComplete);

Also, note the difference between passing a function (as I have been doing, without the ()) vs calling the function (which you've been doing). For more info, see Why is the method executed immediately when I use setTimeout?




回答2:


There seems to be a very common misconception that promise functions like jQuery.when() contain some magical power that they can just "know" when some other function is done. Let me dispell that myth right now. They don't have any magical power. jQuery.when() ONLY takes promises as it's arguments and the reason it requires promises is because those promises will tell jQuery.when() when they are done. When you pass some other type of object to jQuery.when() that isn't a promise, it quite simply has no idea when that other thing is done. It will treat it as a synchronous function that is done as soon as it runs, but if it's not a synchronous function or not a function at all, then jQuery.when() won't do what you want it to.


Rule #1 - You MUST pass promises to jQuery.when(). You aren't doing that. You're passing this to it which is probably the window object. That won't do you any good and jQuery.when() will just resolve immediately, not waiting for anything to finish.

Rule #2 - Promises ONLY work if you write code that resolves or rejects the promise when the asynchronous task is done. Again, there's no magic here. You have to tell the promise when the async task is done. Only then, can the promise do what it's supposed to and make things like .then() handlers work. You have several async operations in your DisplayHdline() function, but you aren't creating a promise or resolving that promise and you aren't keeping track of when all the async operations in that function are done.

Rule #3 - If your underlying framework/infrastructure supports promises and will resolve them for you when operations are done, then by all means use that rather than creating your own promises. In your case, jQuery animations will already create and resolve their own promises. You will want to use that here.


So, if the extent of your problem here is that you want to know when all the animations in DisplayHdline() are done, you can leverage jQuery to help you know that and you can return a promise from that function like this:

function DisplayHdline() {
    var str = "HELP STOP CRUELTY NOW.";
    var spans = '<span>' + str.split(/\s+/).join(' </span><span>') + '</span>';

    return jQuery(spans).hide().appendTo('#vidheadline').each(function(i) {
        jQuery(this).delay(2000 * i).fadeIn('fast').delay(1000).fadeOut(50);
    }).promise();
}

Then, you can call it and know when it's done like this:

DisplayHdline().done(function() {
    // code here to execute when everything in DisplayHdline is done
});

Note that I changed the structure of your code to not pass a callback to DisplayHdline() because this structure is much more flexible. When you return the promise, you can always just add a .done() handler like I've done and it will work like the callback, but you can also do many other things such as chain other actions onto this or combine it with other operations and wait for multiple promises to be done before doing something else, etc... This is the beauty of a standard promise interface as it allows many different types of handling without having to know the internals of the operation.


What jQuery is doing for you here is actually saving you a lot of work. When you do .promise() on a collection that all has animation going on it, jQuery returns to you a single promise that gets resolved when all the underlying object's promises have been resolved, saving you the work of keep track of all of them. It's actually quite useful in this way.




回答3:


It's because your function does not return a promise. You're just using a callback mechanism, promises are used for async calls to avoid callback hell.

You can just change your code to something like this:

DisplayHdLine(function() {
   // When you're inside this function, everything in the DisplayHdLine is done executing
   addComplete();
});

Or even shorter

DisplayHdLine(addComplete);

If you want the callback function to be called when the fading is done, you can turn your jquery.each into a promise and call the callback in the done function.

function DisplayHdline( callback){
    var str = "HELP STOP CRUELTY NOW.";
    var spans = '<span>' + str.split(/\s+/).join(' </span><span>') + '</span>';

    jQuery(spans).hide().appendTo('#vidheadline').each(function(i) {
        jQuery(this).delay(2000 * i).fadeIn('fast').delay(1000).fadeOut(50);
    }).promise().done(callback);
}


来源:https://stackoverflow.com/questions/24549066/tried-when-and-then-no-lucky

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!