357

I have two JS functions. One calls the other. Within the calling function, I'd like to call the other, wait for that function to finish, then continue on. So, for example/pseudo code:

function firstFunction(){
    for(i=0;i<x;i++){
        // do something
    }
};

function secondFunction(){
    firstFunction()
    // now wait for firstFunction to finish...
    // do something else
};

I came up with this solution, but don't know if this is a smart way to go about it.

var isPaused = false;

function firstFunction(){
    isPaused = true;
    for(i=0;i<x;i++){
        // do something
    }
    isPaused = false;
};

function secondFunction(){
    firstFunction()
    function waitForIt(){
        if (isPaused) {
            setTimeout(function(){waitForIt()},100);
        } else {
            // go do that thing
        };
    }
};

Is that legit? Is there a more elegant way to handle it? Perhaps with jQuery?

DA.
  • 39,848
  • 49
  • 150
  • 213
  • 13
    What does `firstFunction` exactly do that makes it asynchronous? Either way - check about promises – zerkms Feb 03 '14 at 01:12
  • 1
    The first function is rapidly updating a score clock every 10th of a second. Which...come to think of it, I suppose we could pre-calculate and then just manually pause the second function call via setTimeout. That said, I can still see a desire to have a pause ability elsewhere. – DA. Feb 03 '14 at 01:17
  • you don't need a pause - google for promises in jquery – zerkms Feb 03 '14 at 01:32
  • @zerkms promises looks interesting! Still investigating browser support... – DA. Feb 03 '14 at 01:36
  • 2
    I also have the same problem. – Vappor Washmade Sep 18 '18 at 18:15
  • I think your solution is still valid today for simple scenario like [mine](https://stackoverflow.com/questions/65737817/asynchronously-wait-for-a-function-to-be-called). –  Jan 15 '21 at 16:16
  • I also need that kind of thing; for an app using file system, I want to call in file replacing function several times in another function and wait for the write process to finnish before calling the function another time. – SkySibe Aug 01 '22 at 14:19

12 Answers12

237

One way to deal with asynchronous work like this is to use a callback function, eg:

function firstFunction(_callback){
    // do some asynchronous work
    // and when the asynchronous stuff is complete
    _callback();    
}

function secondFunction(){
    // call first function and pass in a callback function which
    // first function runs when it has completed
    firstFunction(function() {
        console.log('huzzah, I\'m done!');
    });    
}

As per @Janaka Pushpakumara's suggestion, you can now use arrow functions to achieve the same thing. For example:

firstFunction(() => console.log('huzzah, I\'m done!'))


Update: I answered this quite some time ago, and really want to update it. While callbacks are absolutely fine, in my experience they tend to result in code that is more difficult to read and maintain. There are situations where I still use them though, such as to pass in progress events and the like as parameters. This update is just to emphasise alternatives.

Also the original question doesn't specificallty mention async, so in case anyone is confused, if your function is synchronous, it will block when called. For example:

doSomething()
// the function below will wait until doSomething completes if it is synchronous
doSomethingElse()

If though as implied the function is asynchronous, the way I tend to deal with all my asynchronous work today is with async/await. For example:

const secondFunction = async () => {
  const result = await firstFunction()
  // do something else here after firstFunction completes
}

IMO, async/await makes your code much more readable than using promises directly (most of the time). If you need to handle catching errors then use it with try/catch. Read about it more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function .

Matt Way
  • 32,319
  • 10
  • 79
  • 85
  • 11
    callbacks are inconvenient to deal with asynchrony, promises are much easier and flexible – zerkms Feb 03 '14 at 01:40
  • 1
    While you are right that I shouldn't have used the word best (updated), the convenience of callbacks vs promises depends on the complexity of the problem. – Matt Way Feb 03 '14 at 01:50
  • 5
    It becomes offtopic, but I personally don't see a reason to prefer callbacks these days :-) Cannot remember any of my code written in last 2 years provided callbacks over promises. – zerkms Feb 03 '14 at 01:54
  • 3
    If you want, you can use arrow function in es6 secondFunction(){ firstFunction((response) => { console.log(response); }); } – Janaka Pushpakumara Aug 18 '17 at 04:45
  • @JanakaPushpakumara Updated my old answer. – Matt Way Aug 18 '17 at 09:10
  • if there is any 'big job' inside firstFunction, lets say, an ajax request, it will, probably, fire _callBack() before finish .... I mean, firstFunction will also fire any content in it without wait the previous comand be finishes – Diego Favero Sep 08 '18 at 19:13
  • what if you have no access to the first function? – Noob Oct 19 '20 at 09:03
113

Use async/await :

async function firstFunction(){
  for(i=0;i<x;i++){
    // do something
  }
  return;
};

then use await in your other function to wait for it to return:

async function secondFunction(){
  await firstFunction();
  // now wait for firstFunction to finish...
  // do something else
};
Fawaz
  • 3,404
  • 3
  • 17
  • 22
  • 15
    for those of us stuck supporting older browsers, IE doesn't support async/await – kyle Oct 24 '18 at 20:35
  • Can this be used outside both functions, as in, `$(function() { await firstFunction(); secondFunction(); });` ? – Lewistrick Jan 21 '19 at 11:59
  • 2
    @Lewistrick Just remember `await` can only be used inside an `async` method. So if you make your parent function `async` you can call as many `async methods` inside with or without `await` that you want to. – Fawaz Jan 21 '19 at 12:53
  • Is it possible to `await` a `setTimeout`? – Shayan Dec 26 '19 at 18:45
  • 1
    @Shayan yes it is, wrap setTimeout in another function which resolves a promise after timeout. – Fawaz Dec 27 '19 at 13:27
  • What is `firstFunction()` is doing multiple uploads... how will `secondFunction()` know when it has completed all its jobs? – volume one May 08 '20 at 10:07
  • @volumeone See the `return` statement in first function – Fawaz May 08 '20 at 10:40
  • Should `async function firstFunction()` instead be `function firstFunction()`? – velkoon May 20 '21 at 00:53
  • @velkoon Are you saying that because there is no `await` inside there ? this is only pseudo code so in actual implementation there will be an `await` or some blocking operation for which we want to wait. – Fawaz May 21 '21 at 07:30
  • What happens if firstFunction has parameters? How to call it with await? – A7x Nov 30 '21 at 22:39
  • @A7x That should work like a function normally passes parameters. – Fawaz Dec 02 '21 at 05:34
  • What is IE? in 2022 – Martin Apr 02 '22 at 08:14
  • @kyle I'm just circling back to say that IE is no longer with us :D So essentially my approach was future proof ;) – Fawaz Jun 23 '22 at 20:57
  • In this specific example (I have a very similar code), what is the use of `async` on `firstFunction` ? – iBoolGuy Dec 12 '22 at 11:55
84

An elegant way to wait for one function to complete first is to use Promises with async/await function.


  1. Firstly, create a Promise. The function I created will be completed after 2s. I used setTimeout in order to demonstrate the situation where the instructions would take some time to execute.
  2. For the second function, you can use async/await a function where you will await for the first function to complete before proceeding with the instructions.

Example:

    //1. Create a new function that returns a promise
    function firstFunction() {
      return new Promise((resolve, reject) => {
          let y = 0
          setTimeout(() => {
            for (i=0; i<10; i++) {
               y++
            }
             console.log('Loop completed.')  
             resolve(y)
          }, 2000)
      })
    }
    
    //2. Create an async function
    async function secondFunction() {
        console.log('Before promise call.')
        //3. Await for the first function to complete
        const result = await firstFunction()
        console.log('Promise resolved: ' + result)
        console.log('Next step.')
    }; 

    secondFunction()

Note:

You could simply resolve the Promise without any value like so resolve(). In my example, I resolved the Promise with the value of y that I can then use in the second function.

Jakub A Suplicki
  • 4,586
  • 1
  • 23
  • 31
59

Notice

This answer is outdated by today's standards. Consider using native JavaScript Promises and async/await syntax instead.


It appears you're missing an important point here: JavaScript is a single-threaded execution environment. Let's look again at your code, note I've added alert("Here"):

var isPaused = false;

function firstFunction(){
    isPaused = true;
    for(i=0;i<x;i++){
        // do something
    }
    isPaused = false;
};

function secondFunction(){
    firstFunction()

    alert("Here");

    function waitForIt(){
        if (isPaused) {
            setTimeout(function(){waitForIt()},100);
        } else {
            // go do that thing
        };
    }
};

You don't have to wait for isPaused. When you see the "Here" alert, isPaused will be false already, and firstFunction will have returned. That's because you cannot "yield" from inside the for loop (// do something), the loop may not be interrupted and will have to fully complete first (more details: Javascript thread-handling and race-conditions).

That said, you still can make the code flow inside firstFunction to be asynchronous and use either callback or promise to notify the caller. You'd have to give up upon for loop and simulate it with if instead (JSFiddle):

function firstFunction()
{
    var deferred = $.Deferred();
    
    var i = 0;
    var nextStep = function() {
        if (i<10) {
            // Do something
            printOutput("Step: " + i);
            i++;
            setTimeout(nextStep, 500); 
        }
        else {
            deferred.resolve(i);
        }
    }
    nextStep();
    return deferred.promise();
}

function secondFunction()
{
    var promise = firstFunction();
    promise.then(function(result) { 
        printOutput("Result: " + result);
    });
}

On a side note, JavaScript 1.7 has introduced yield keyword as a part of generators. That will allow to "punch" asynchronous holes in otherwise synchronous JavaScript code flow (more details and an example). However, the browser support for generators is currently limited to Firefox and Chrome, AFAIK.

ADTC
  • 8,999
  • 5
  • 68
  • 93
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • 3
    You saved me. $.Deferred() is what I am have been gunning for. Thanks – Temitayo Aug 16 '17 at 16:15
  • @noseratio I tried this. But the waitForIt method does not get called at all. What am I doing wrong? – vigamage Jan 07 '20 at 11:36
  • @vigamage, could you provide a link to jsfiddle or codepen of what you've tried? – noseratio Jan 07 '20 at 19:52
  • @LodeAlaert this answer is a bit outdated by today's standards. You should be using native JavaScript Promises and async/await syntax. Lots of good tutorials on the web, e.g., try www.freecodecamp.org. – noseratio Jul 14 '21 at 10:08
30

I wonder why no one have mentioned this simple pattern? :

(function(next) {
  //do something
  next()
}(function() {
  //do some more
}))

Using timeouts just for blindly waiting is bad practice; and involving promises just adds more complexity to the code. In OP's case:

(function(next) {
  for(i=0;i<x;i++){
    // do something
    if (i==x-1) next()
  }
}(function() {
  // now wait for firstFunction to finish...
  // do something else
}))

a small demo -> http://jsfiddle.net/5jdeb93r/

davidkonrad
  • 83,997
  • 17
  • 205
  • 265
  • 2
    This worked for me and yes. Good point, I wonder why no one mentioned this. Not all the time one wants to use sync/async – Nation Dec 15 '20 at 05:01
  • I'm unfamiliar with JQuery (which I think this uses, based on the settings in the jsfiddle demo) and am quite perplexed with how this works. Can someone explain why the functions don't have a name, and why this entire code snippet is in parentheses? `(function(next)...)` Also, how does `next` work when it is never declared? Is it a native JQuery function? – velkoon May 19 '21 at 19:58
  • @velkoon, it has _nothing_ to do with jQuery but is pure javascript as it is intended. The struct or pattern is called a [self-invoking function](https://blog.mgechev.com/2012/08/29/self-invoking-functions-in-javascript-or-immediately-invoked-function-expression/). The `next` param is actually declared, if you look carefully, the second `function()` is what is injected as `next` by the function itself. Anywhere you need something to be executed after something else, you can copy paste the first 4 lines and simply place the code you want executed between the two `{...}` literals. – davidkonrad May 20 '21 at 01:40
  • @davidkonrad what if the first function fails, of if I dont want to wait for the first function not more then 2 seconds? – Jaber Al Nahian Nov 17 '22 at 06:04
  • 1
    Hey @JaberAlNahian, that is actually a completely different scenario than the asked question. In the solution above, since both functions is within the same scope, I would set an `let executed = false`-flag, and wrap the first function into a `setTimeout()`; if `executed` not is true when timeout is met, execute `next()`, and set `executed` to true .. (not tested) And, oh - change to `if (i==x-1 && !executed) next()` to prevent execution twice ... – davidkonrad Nov 18 '22 at 14:00
7

The only issue with promises is that IE doesn't support them. Edge does, but there's plenty of IE 10 and 11 out there: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise (compatibility at the bottom)

So, JavaScript is single-threaded. If you're not making an asynchronous call, it will behave predictably. The main JavaScript thread will execute one function completely before executing the next one, in the order they appear in the code. Guaranteeing order for synchronous functions is trivial - each function will execute completely in the order it was called.

Think of the synchronous function as an atomic unit of work. The main JavaScript thread will execute it fully, in the order the statements appear in the code.

But, throw in the asynchronous call, as in the following situation:

showLoadingDiv(); // function 1

makeAjaxCall(); // function 2 - contains async ajax call

hideLoadingDiv(); // function 3

This doesn't do what you want. It instantaneously executes function 1, function 2, and function 3. Loading div flashes and it's gone, while the ajax call is not nearly complete, even though makeAjaxCall() has returned. THE COMPLICATION is that makeAjaxCall() has broken its work up into chunks which are advanced little by little by each spin of the main JavaScript thread - it's behaving asychronously. But that same main thread, during one spin/run, executed the synchronous portions quickly and predictably.

So, the way I handled it: Like I said the function is the atomic unit of work. I combined the code of function 1 and 2 - I put the code of function 1 in function 2, before the asynch call. I got rid of function 1. Everything up to and including the asynchronous call executes predictably, in order.

THEN, when the asynchronous call completes, after several spins of the main JavaScript thread, have it call function 3. This guarantees the order. For example, with ajax, the onreadystatechange event handler is called multiple times. When it reports it's completed, then call the final function you want.

I agree it's messier. I like having code be symmetric, I like having functions do one thing (or close to it), and I don't like having the ajax call in any way be responsible for the display (creating a dependency on the caller). BUT, with an asynchronous call embedded in a synchronous function, compromises have to be made in order to guarantee order of execution. And I have to code for IE 10 so no promises.

Summary: For synchronous calls, guaranteeing order is trivial. Each function executes fully in the order it was called. For a function with an asynchronous call, the only way to guarantee order is to monitor when the async call completes, and call the third function when that state is detected.

For a discussion of JavaScript threads, see: https://medium.com/@francesco_rizzi/javascript-main-thread-dissected-43c85fce7e23 and https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

Also, another similar, highly rated question on this subject: How should I call 3 functions in order to execute them one after the other?

kermit
  • 1,621
  • 1
  • 14
  • 14
  • 11
    To the downvoter(s), I'd be curious to know what's wrong with this answer. – kermit Jul 21 '18 at 19:05
  • 1
    This is an old reply, and I haven't voted on it, but it could be made clearer if you provide insight into the before/after of functions 1, 2, 3 - instead of only describing it with words. Also, using callbacks could make sense - that way, you can pass function1 and function3 to function2, so that one is executed at the start, and the other when the async operation returns. – tucuxi Oct 25 '21 at 07:57
5

Can use Promise

A promise is a JavaScript construct that represents a future unknown value. It could be the result from an API call, or it could be an error object from a failed network request. You're guaranteed to get something.

const promise = new Promise((resolve, reject) => {
    // Make a network request
   if (yourcondition=="value") {
      
   } else {
      reject(error);
   }
})

promise.then(res => {
    //if not rejected, code

}).catch(err => {
    //return false; 
})

A promise can have

fulfilled - action successfully completed

rejected - action failed

pending - neither action has been completed

settled - has been fulfilled or rejected

Merrin K
  • 1,602
  • 1
  • 16
  • 27
2

Your main function will call firstFunction then on complete of it your next function will execute.

async firstFunction() {
            const promise = new Promise((resolve, reject) => {
                for (let i = 0; i < 5; i++) {
                    // do something
                    console.log(i);
                    if (i == 4) {
                        resolve(i);
                    }
                }
            });
            const result = await promise;
        }
    
        second() {
            this.firstFunction().then( res => {
                // third function call do something
                console.log('Gajender here');
            });
        }
Halo
  • 1,730
  • 1
  • 8
  • 31
Gajender Singh
  • 1,285
  • 14
  • 13
1

I wrote this after two days of trying. This is the best way try like this:

var recv = -1;

async function First_fn() {

    var answ = await Second_fn();
    console.log(answ);
    recv = -1;

}

async function Second_fn() {
    var parm = 1;
    var adrss = 2;

    await Third_fn(adrss, parm);
    // Using the following loop will minimize the waiting time
    for (let i = 0; i < 180; i++) {
        if (recv !== -1) {
            console.log(recv);
            break;
        }
        else {
            await new Promise(resolve => setTimeout(resolve, 500));
        }
    }
    return recv;
}

async function Third_fn(adrss, parm) {
    //someting to do => result
    //for example:
    let result = adrss + parm;
    recv = result; // recv is global varable
 }
 
First_fn(); 
  • 2
    Your answer could be improved by adding more information on what the code does and how it helps the OP. – Tyler2P Jun 01 '22 at 08:34
0

This what I came up with, since I need to run several operations in a chain.

<button onclick="tprom('Hello Niclas')">test promise</button>

<script>
    function tprom(mess) {
        console.clear();

        var promise = new Promise(function (resolve, reject) {
            setTimeout(function () {
                resolve(mess);
            }, 2000);
        });

        var promise2 = new Promise(async function (resolve, reject) {
            await promise;
            setTimeout(function () {
                resolve(mess + ' ' + mess);
            }, 2000);
        });

        var promise3 = new Promise(async function (resolve, reject) {
            await promise2;
            setTimeout(function () {
                resolve(mess + ' ' + mess+ ' ' + mess);
            }, 2000);
        });

        promise.then(function (data) {
            console.log(data);
        });

        promise2.then(function (data) {
            console.log(data);
        });

        promise3.then(function (data) {
            console.log(data);
        });
    }

</script>
  • Please add at least jus a high level comments for description of the given snippet. This is to explain how your code addresses the problem. – Alex Pappas Oct 24 '19 at 03:13
  • The problem was to run a second function after the first one. I show how run a second function after the first one, and also how to run a third function after the second one. I made three functions, to make it easy to understand what code is required. – Niclas Arnberger Nov 26 '19 at 15:18
-1

Try this

function firstFunction(){
    
    // do something  
    X=true;
    return X;
}

function secondFunction(){
    X=false;
    X=firstFunction();
    setTimeout( function() {
        if(X==true){
            // do something else
        }else{
            // do something else
        }
        alert(X); // To check X 
       
    }, 100); // Can increase time delay 200,300, ...
}

Increase the time from 100 to 200, 300, ... Based on the time required for the firstFunction to complete

Merrin K
  • 1,602
  • 1
  • 16
  • 27
-1

I had the same Issue.
My Solution was to call my second function at the end of my async function,
since you already have a For loop in your async function,
you could call your second function once the highest value of the loop condition has been reached
which in your case is
i = x-1 so:

function firstFunction(){
  for(i=0;i<x;i++){
     // do something
     if(i === x - 1){
       // do something else or call secondFunction();
     }
  }
}
Jachub123
  • 1
  • 1