0

I am doing a hobby project in NodeJS and Express, but I am overwhelmed by dealing with asynchronous calls. I have encountered a bug that I would like to bounce with the community.

I currently have this layout using Express to which I am sending post requests to.

Express (backend)

app.post("/", async (req, res) => {
    const createDocument = (args1) => {

        // declare some variables ...
        // for loop ...
        // (quite fast)

        loadFile(args2, async () => {

            // upload a file (quite slow)
            await upload(file, filePath)

            //send post request to third party (quite fast)
            let res = await axios.post(url, data, {
                headers: {
                    'X-Auth-Token': KEY
                }
            }).then(res => console.log('success')).catch(error => console.log('failure'))
        })
    }

    const args1 = "someargs"

    await new Promise(resolve => setTimeout(resolve, 2000))
    await createDocument(args1)

    res.end()
})

React (frontend)

const saveDocButtonClicked = useCallback(async (event) => {

    // do some stuff ...

    await axios.post('/', {
        headers: {
            'Content-Type': 'application/json'
        },
        jsonData
    }).then(res => console.log('Data sent')).catch(err => console.log(err.data))

    // do some other stuff ...

}

I want the React app to wait, and not proceed before getting a proper response from the API call to the Express backend.

And I want the Express app to give a proper response only when it has performed all of its tasks.

This has worked fine so far for smaller files, but as they increase in size, they no longer get saved / stored in the database.

The key difference I noticed is that in these bad cases, the strings success or failure which should come from this piece of code in the Express backend; .then(res => console.log('success')).catch(error => console.log('failure')) no longer gets outputted. So somewhere the asynchronous events are probably jumping the gun.

I am sure that I have made tons of mistakes, please feel free to point them out, I would love to learn this, I am such a freshman on asynchronous calls.

2
  • 3
    I think the issues is with createDocument, You should return the promise from that function which would resolve whenever loadFile completes. Hope that helps Commented Jun 27, 2021 at 16:28
  • Okay how would that look like in code? I have a few ideas, but can't write them here in the small comments window. Commented Jun 27, 2021 at 16:56

3 Answers 3

1

Returning promise from createDocument will allow the await createDocument(args1) to wait until it completed execution

app.post("/", async (req, res) => {
const createDocument = (args1) => {
    return new Promise((resolve,reject)=>{
        // declare some variables ...
        // for loop ...
        // (quite fast)

        loadFile(args2, async () => {

            // upload a file (quite slow)
            await upload(file, filePath)

            //send post request to third party (quite fast)
            let res = await axios.post(url, data, {
                headers: {
                    'X-Auth-Token': KEY
                }
            }).then(res => console.log('success')).catch(error => console.log('failure'))
            resolve(res);
            //TODO:: Reject if some error occurs;
        })
    });
}

const args1 = "someargs"

await new Promise(resolve => setTimeout(resolve, 2000))
await createDocument(args1)

res.end()
})
Sign up to request clarification or add additional context in comments.

Comments

0

Using async-await and with then/catch is the bad way to go for this kind of thing. With await you can do the job

try {
  const response = await axios.post('/', {
      headers: {
        'Content-Type': 'application/json'
      },
      jsonData
  })
  // Here is your data after response completed
  const data  = response.json()
} catch(err) {
  console.log(err)
} 

Or you can remove async/await and simply use then/catch

Comments

0

Your code seems syntactically correct (though it can be better by following some async/await best practices - but those should not affect the logic of your app). Can you provide some sample input, output, and your expected outputs so I can understand the question better ?

In the mean time, I think that it can just be upload() function is slow, especially for bigger files, so you just need to wait more before "success" or "failure" is logged

Edit: I figured something with the callback flow that did not go with the async/await flow. Seems like the createDocument did not wait, or know to wait for loadFile to finish, because loadFile stuff is "hidden" behind a callback. So I altered createDocument to return a Promise:

app.post("/", async (req, res) => {
    const createDocument = (args1) => {
        // Return a promise that waits for loadFile
        return new Promise((resolve, reject) => {
            // declare some variables ...
            // for loop ...
            // (quite fast)

            loadFile(args, () => {
                // I dont like using async with callback, so I'mma use .then()
                function makeAxiosRequest() {
                    return axios.post(url, data, {
                        headers: {
                            "X-Auth-Token": KEY,
                        },
                    });
                }
                // Only resolve createDocument after loadFile's stuff is finished
                upload(file, filePath)
                    .then(() => makeAxiosRequest())
                    .then(() => console.log("Success"))
                    .catch((err) => console.log("Failure"))
                    .finally(resolve());
            });
        });
    };

    const args1 = "someargs";

    await new Promise((resolve) => setTimeout(resolve, 2000));

    await createDocument(args1);

    // I like sending something to frontend for better debug experience
    return res.json({ message: "Respond now ends" });
});

6 Comments

Hey I can create an edit on the original question with some sample inputs and outputs. The strange thing however, is that "success" or "failure" is never outputted, even after several hours.
I figure something could be wrong with how you defined your loadFile function. It looks both async yet also uses callback at the same time. If you make an edit, can you include some details on how your loadFile function is defined ?
That function was actually not defined by me, but is a build in function of a package that I am using, essentially I am inputting it with a long base64 string and when it has fully loaded, it will trigger the callback.
I figured something with the callback flow that did not go with the async/await flow. Seems like the createDocument did not wait, or know to wait for loadFile to finish, because loadFile stuff is "hidden" behind a callback. Can you check my edit to see if it works ?
Hey Bao, sure I will check
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.