45

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?

Pang
  • 9,564
  • 146
  • 81
  • 122
user2878249
  • 623
  • 1
  • 6
  • 10
  • What if at the end of `function Typer()`, after `100);` insert `playBGM();` ? Here example http://jsfiddle.net/GkUEN/99/ – Andris Jul 07 '15 at 15:01

4 Answers4

77

You can use below code

$.when( Typer() ).done(function() {
       playBGM();
});
Pradeep
  • 4,612
  • 10
  • 38
  • 50
  • 1
    How can I combine multiple functions? e.g. when 1 done start 2 when 2 done start 3 – JonSnow Apr 21 '16 at 08:53
  • This answer is not complete, it won't work on its own. A deferred object needs defining in the Typer function, and any other function in the chain, along with resolving, and returning the promise. Only then will the sound play after the typer function completes. @SchweizerSchoggi to combine multiple functions: `Typer().then(playBGM).then(ThirdFunction).then(yetAnotherFunction);` Make sure you're using JQuery 3.2.1 as this will NOT work with Jquery 1.71 as I just wasted 15 minutes on JSFiddle discovering. – hiJump Aug 15 '17 at 08:34
  • Why this code is not working for me? Am I missing any library or something?! :/ – Mojtaba Rezaeian Dec 31 '18 at 02:31
  • how to pass arguments from first function to second function – Imran Mohammed Apr 21 '21 at 06:41
37

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.

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();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<div id="message">
</div>
<audio id="bgm" src="http://www.freesfx.co.uk/rx2/mp3s/9/10780_1381246351.mp3">
</audio>

JSFIDDLE

Hitesh Tripathi
  • 856
  • 1
  • 11
  • 23
Ionică Bizău
  • 109,027
  • 88
  • 289
  • 474
4

You could also use custom events:

function Typer() {
    // Some stuff

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


$(anyDomElement).on("myCustomEvent", function() {
    // Some other stuff
});
Jerome
  • 49
  • 2
3

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.

sqlchild
  • 8,754
  • 28
  • 105
  • 167
hiJump
  • 1,379
  • 1
  • 9
  • 8
  • "THIS" keyword is invalid here in clearInterval(this) – sqlchild Apr 04 '18 at 04:52
  • sqlchild, okay I didn't know I just took that part from the OP's function. It still works though, I ran it before posting and it didn't throw any errors. But if you say it's invalid I won't argue! – hiJump Apr 11 '18 at 12:49