Execute jQuery function after another function com

2019-01-06 11:12发布

问题:

I want to execute a custom jQuery function after another custom function completes
The first function is used for creating a "typewriting" effect

function Typer()
{
    var srcText = 'EXAMPLE ';
    var i = 0;
    var result = srcText[i];
    setInterval(function() {
        if(i == srcText.length) {
            clearInterval(this);
            return;
        };
        i++;
        result += srcText[i].replace("\n", "<br />");
        $("#message").html( result);
    },
    100);

}

and the second function plays a sound

function playBGM()
{
    document.getElementById('bgm').play();
}

I am calling the functions one after the another like

Typer();
playBGM();

But the sound starts playing as the text is getting typed. I want to play the sound only AFTER the typewriting has finished.

Here is what I have tried: http://jsfiddle.net/GkUEN/5/

How can I fix this?

回答1:

You should use a callback parameter:

function Typer(callback)
{
    var srcText = 'EXAMPLE ';
    var i = 0;
    var result = srcText[i];
    var interval = setInterval(function() {
        if(i == srcText.length - 1) {
            clearInterval(interval);
            callback();
            return;
        }
        i++;
        result += srcText[i].replace("\n", "<br />");
        $("#message").html(result);
    },
    100);
    return true;


}

function playBGM () {
    alert("Play BGM function");
    $('#bgm').get(0).play();
}

Typer(function () {
    playBGM();
});

// or one-liner: Typer(playBGM);

So, you pass a function as parameter (callback) that will be called in that if before return.

Also, this is a good article about callbacks.

JSFIDDLE



回答2:

You can use below code

$.when( Typer() ).done(function() {
       playBGM();
});


回答3:

You could also use custom events:

function Typer() {
    // Some stuff

    $(anyDomElement).trigger("myCustomEvent");
}


$(anyDomElement).on("myCustomEvent", function() {
    // Some other stuff
});


回答4:

Deferred promises are a nice way to chain together function execution neatly and easily. Whether AJAX or normal functions, they offer greater flexibility than callbacks, and I've found easier to grasp.

function Typer()
{
var dfd = $.Deferred();
    var srcText = 'EXAMPLE ';
    var i = 0;
    var result = srcText[i];

UPDATE :

////////////////////////////////

  var timer=    setInterval(function() {
                    if(i == srcText.length) {

    // clearInterval(this);


       clearInterval(timer);

////////////////////////////////


   dfd.resolve();
                        };
                        i++;
                        result += srcText[i].replace("\n", "<br />");
                        $("#message").html( result);
                },
                100);
              return dfd.promise();
            }

I've modified the play function so it returns a promise when the audio finishes playing, which might be useful to some. The third function fires when sound finishes playing.

   function playBGM()
    {
      var playsound = $.Deferred();
      $('#bgm')[0].play();
      $("#bgm").on("ended", function() {
         playsound.resolve();
      });
        return playsound.promise();
    }


    function thirdFunction() {
        alert('third function');
    }

Now call the whole thing with the following: (be sure to use Jquery 1.9.1 or above as I found that 1.7.2 executes all the functions at once, rather than waiting for each to resolve.)

Typer().then(playBGM).then(thirdFunction);  

Before today, I had no luck using deferred promises in this way, and finally have grasped it. Precisely timed, chained interface events occurring exactly when we want them to, including async events, has never been easy. For me at least, I now have it under control thanks largely to others asking questions here.