Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way to wait for one function to finish before continuing?

People also ask

How do you wait for a function to finish before continuing JavaScript?

Use async/await to Wait for a Function to Finish Before Continuing Execution. Another way to wait for a function to execute before continuing the execution in the asynchronous environment in JavaScript is to use async/wait .

How do you make a function wait for a second?

To delay a function execution in JavaScript by 1 second, wrap a promise execution inside a function and wrap the Promise's resolve() in a setTimeout() as shown below. setTimeout() accepts time in milliseconds, so setTimeout(fn, 1000) tells JavaScript to call fn after 1 second.

How do you wait for setTimeout to finish?

Use of setTimeout() function: In order to wait for a promise to finish before returning the variable, the function can be set with setTimeout(), so that the function waits for a few milliseconds. Use of async or await() function: This method can be used if the exact time required in setTimeout() cannot be specified.

How do you wait for loop to finish?

Your loop needs to wait for the asynchronous task to complete on each round of the for loop. To make this happen, mark your function asynchronous using the async keyword, and place an await keyword in front of the action you want to wait for.


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 .


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
};

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.


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.


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/