Wait for function to complete before moving on

Viewed 617

I have these 3 functions that need to run in order. However, since the first function has a loop in it, the 2nd and 3rd functions are finishing before the data from the 1st function is available. How can I refactor this to guarantee each one completes in order before the next starts? In the past using .then has given me what I need. But this time it's not completing in the right order.

mainFunction() {
        fetch(API_URL + `/dataToGet`)
            .then((res) => {
                if (!res.ok) {
                    throw new Error();
                }
                return res.json();
            })
            .then((result) => {
                this.setState({data: result}, () => this.1stFunction());
                console.log(result);
            })
            .catch((error) => {
                console.log(error);
            })
            .then(this.2ndFunction())
            .catch((error) => {
                console.log(error);
            })
            .then(this.3rdFunction());
  }
firstFunction(){
for (let i = 0; i < data.length; i++){
            for (let j = 0; j < 8; j++){
               //...grabbing data and saving to variables to be used in next steps... 
            }
        }
}

secondFunction(){
... wait until firstFunction is completed and then do something with data...
}

thridFunction(){
... wait until secondFunction is complete and then do something else with that data...
}

5 Answers

You need to pass the function itself, not its result to then:

.then(this.the2ndFunction)

Otherwise you will probably execute your 2nd function before the fetch event returns.

Moreover, using promises for what appear to be two strictly sequential functions is a bit unnecessary.

Async and await will wait for one call to get complete and then only it will move to the next line in function.

async mainFunction() {
  try{
    const api = await fetch(API_URL + `/dataToGet`);
    const fistUpdate = await this.1stFunction(api);
    const secondUpdate = await this.2stFunction(fistUpdate);
    const thirdUpdate = await this.3stFunction(secondUpdate);
  } catch(){
  //error handling
  }
}

If all your functions are synchronous you can do

const res = this.1stFunction();
this.setState({data: result}, () => res);
this.2ndFunction()
this.3rdFunction()

if they are async

async function function_name(){
    const res = await this.1stFunction();
    this.setState({data: result}, () => res);
    await this.2ndFunction()
    await this.3rdFunction()
}

Make 1st, 2nd, and 3rd functions return Promise.resolve(), then:

mainFunction() {
        fetch(API_URL + `/dataToGet`)
            .then((res) => {
                if (!res.ok) {
                    throw new Error();
                }
                return res.json();
            })
            .then((result) => {
                this.setState({data: result}, () => {
                    this.1stFunction().then(() => {
                        this.2ndFunction().then(() => {
                            this.3rdFunction();
                        });
                    });
                });
                console.log(result);
            })
            .catch((error) => {
                console.log(error);
            });
  }

Doing .then(this.2ndFunction()) is wrong, because the function will be executed immediately

Are the 3 functions synchronous ? if yes you can just call these functions inside the setState callback

mainFunction() {
  fetch(API_URL + `/dataToGet`)
    .then((res) => {
      if (!res.ok) {
        throw new Error();
      }
      return res.json();
    })
    .then((result) => {
      this.setState({data: result}, () => {
        this.1stFunction();
        this.2ndFunction();
        this.3rdFunction();
      });
    })
    .catch((error) => console.log(error));
}

If the functions are asynchronous, you simply need to return a Promise from these functions and update your code like this :

.then((result) => {
  return new Promise((resolve, reject) => {
    this.setState({data: result}, () => {
      this.1stFunction().then(resolve, reject);
    });
  }
})
.catch(console.log)
.then(this.2ndFunction)
.catch(console.log)
.then(this.3ndFunction)
.catch(console.log)
Related