Nick Wild
Nick Wild

Reputation: 575

Javascript Async Await wait for two functions to complete

I am struggling to get my head around async/await.

I have the following code which calls:

                const scriptURL =
                        'GOOGLE SCRIPT URL'
                const form = document.forms.emailform
                fetch(scriptURL, { method: 'POST', body: new FormData(form) })
                        .then(response => {
                                console.log('Success!', response)
                                setFormSuccess(1)
                        })
                        .catch(error => {
                                console.error('Error!', error.message)
                                setFormSuccess(2)
                        })
        } 

but I need to wait for the results from both these functions before I call another function to open a modal and pass in the results of these two functions.

Can anybody help me please?

Many Thanks

async function onSubmit() {
                        setTimeout(() => {
                                submitHandler()
                                childRef.current.upload()
                        }, 1000)
                }
                //I want to wait for onSubmit to complete and then call another function which sets state and then launches a modal 
                

EDIT: I for got to mention in the original question that I have tried await in all of the functions I call, but none of them work

Upvotes: 0

Views: 1315

Answers (4)

Kevin Kreps
Kevin Kreps

Reputation: 758

I think you are just missing some "await" statements. Also I modified the timeout.

async function onSubmit() {
                    let sleep = function (ms) {
                        return new Promise(resolve => setTimeout(resolve, ms))
                    }
                    await sleep(1000)
                    await submitHandler()
                    await childRef.current.upload()
            }
            //I want to wait for onSubmit to complete and then call another function which sets state and then launches a modal 
            

Also in the submitHandler() you are not correctly using async-await. You are using the .then methods, which cannot be easily combined with the await.

    async submitHandler() {
            const scriptURL = 'GOOGLE SCRIPT URL'
            const form = document.forms.emailform
            try {
                let response = await fetch(scriptURL, { method: 'POST', body: new FormData(form) })
                console.log('Success!', response)
                setFormSuccess(1)
            } catch(error) {
                console.error('Error!', error.message)
                setFormSuccess(2)
            }
    } 

If you want to still catch errors, you have to wrap the fetch in a try block.

Upvotes: 1

Filip
Filip

Reputation: 143

Your function should return Promise. So return your fetch()

submitHeader(){
      const scriptURL =
                    'GOOGLE SCRIPT URL'
            const form = document.forms.emailform
           return fetch(scriptURL, { method: 'POST', body: new FormData(form) })
                    .then(response => {
                            console.log('Success!', response)
                            setFormSuccess(1)
                            return response;
                    })
                    .catch(error => {
                            console.error('Error!', error.message)
                            setFormSuccess(2)
                    })
    } 

So at you main function you could

async function onSubmit() {
                    setTimeout(() => {
                            const response = await submitHandler()
                            // Your response will be available here
                            console.log(response);
                            childRef.current.upload()
                    }, 1000)
            }

Upvotes: 0

Riwen
Riwen

Reputation: 5190

You can use Promise.all() to await multiple Promises, like so

const result = await Promise.all([submitHandler(), childRef.current.upload()]);

Upvotes: 1

Vivick
Vivick

Reputation: 4991

The first thing is that you need to mark the callback to setTimeout as async if you want to await inside it.

But setTimeout uses callbacks and thus deviate from the control flow you desire. Thus I'd use a simple promise wrapper to make it happen :

const promiseSetTimeout = (cb, delay) => new Promise((resolve, reject) => {
  setTimeout(async () => {
    const ret = await cb();
    resolve(ret);
  }, delay);
});

Thus you can await on it and have the desired control flow.

function onSubmit() {
  return promiseSetTimeout(async () => {
    await submitHandler();
    await childRef.current.upload();
  }, 1000);
}

Upvotes: 0

Related Questions