How to use async/await to properly link multiple functions in Javascript

How to use async/await to properly link multiple functions in Javascript? The following article will introduce some methods to correctly link multiple functions in Javascript with await/async. I hope it will be helpful to everyone.

In addition to my work at electrade, I also helped a friend’s team complete their project. Recently, we wanted to build a Craiglist-style anonymous email relay for this project, which contains the “serverless” Google Firebase Function (same as AWS Lambda, Azure Function, etc.). So far, I’ve found with .then() easier to think callback processing asynchronous operation, but I would like to use async/await, because it reads more clearly. I find most articles about linking multiple functions useless because they tend to post incomplete demo code that is copied and pasted from MSDN. There are some hard-to-debug pitfalls on async/await, because I encountered all these pitfalls, so I will post my full code here and explain my learning process.

This is working code that connects multiple functions, waits for all issues to be resolved, and then sends the result. The main errors are:

  1. Each async function myFunction(){ <your code here> } statement automatically the asynchronous functions of the entire code (i.e., <your code here>) in the package new Promise, and then converted into return x, and added to the code resolve(x). But you still need to wait outside (ie let y = await myFunction()) or it won’t actually wait. This debugging is very annoying.
  2. In the cloud function, you must send with res.send() the response, otherwise the function will consider it a failure and re-run it.

The following code does these things:

  • We have two normal sync function getFieldsFromRequest() and extractCourseIdFromEmailAddress()- there is no problem.

  • Then we need to async function getEmailOfCourseWithCourseId() email address acquisition program from Firestore. We do not know how long it takes to obtain content from Firestore, so it is async, we need to run the next two functions and return (or resolve to Promise) courseEmail.

  • The next two functions saveToCloudFirestore() and sendEmailInSendgrid() can not be in getEmailOfCourseWithCourseId() operation before and returned courseEmail, otherwise they will be considered courseEmail undefined, so everything becomes terrible. By awaiting the above function getEmailOfCourseWithCourseId () and passing courseEmail , these functions (and the if operator) will wait until this happens (that is, resolved), and then run.

  • Finally, run saveToCloudFirestore() and sendEmailInSendgrid() before and return their values, can not be sent res.send(), otherwise our entire cloud function will be interrupted before completion. To this end, we will saveToCloudFireStore(), and sendEmailInSendgrid() to save a response (return to their contents) to the variable , which is the sole purpose is to mark when the above function is completed. This replaces it in a sense .then(): it waits for these two variables (savedToCloud and sentEmail) to “arrive” (their Promise has been resolved) and then runs res.send().

  • For readability, I have removed the try / catch wrapper that you should do in practice. You should never catch errors, but removing them makes the async / await concept easier to understand.

// this is the cloud function you can call over HTTP. 
// It is basically for email relay:

// it gets an email from sendgrid, parses the fields, 
// looks up the real email with the courseId,

// saves to FireStore and sends and email with sendgrid.
// Finally, it sends a res.send () to end the cloud function

// {* import a bunch of shit *}

// main function
exports.emailFunction = functions.https.onRequest (async (req, res) => {
  let fields = getFieldsFromRequest (req); // sync
  let courseId = extractCourseIdFromEmailAddress (fields); // sync
  let courseEmail = await getEmailOfCourseWithCourseId (courseId); // async
  let savedToCloud = await saveToCloudFirestore (fields, courseEmail, courseId); // async
  let sentEmail = await sendEmailWithSendgrid (fields, courseEmail); // async
  res.status (200) .send (savedToCloud, sentEmail); 
  // Once sentEmail and saveToCloud have been returned (aka promises have been resolved, 
  // aka their functions have been run), res.send () will run so Firebase / SendGrid 
  // know that func worked. 
});

// Helper functions below
function getFieldsFromRequest (req) {// sync
    let fields = readTheFieldsFromReqWithBusboy (req)
    return fields;
}

function extractCourseIdFromEmailAddress (fields) {// sync
    let courseId = fields.to.substring (0, fields.to.indexOf ('@'));
    return courseId;
}

async function getEmailOfCourseWithCourseId (courseId) {// async important
    let courseData = await database.get (courseId)
    let courseEmail = courseData.email;
    return courseEmail;
    // due to function being labeled async above, this is the equivalent of
    // wrapping the whole function in 'return new Promise (resolve) => ()' and 
    // then returning a 'resolve (result)'
}

async function sendEmailWithSendgrid (fields, courseEmail) {// async important
    let msg = {to: courseEmail, from: fields.from, text: fields.text}
    let sentEmail = await sendgrid.send (msg)
    return sentEmail; 
    // due to function being labeled async above, 
    // this is the equivalent of wrapping the whole function in
    // 'return new Promise (resolve) => ()' and then returning a 'resolve (result)'
}

async function saveToCloudFirestore (fields, courseEmail, courseId) {// async important
    let savedToCloud = await database.add (fields, courseEmail, courseId)
    return savedToCloud;
}

Finally,** with try {}catch {}the package last three asynchronous functions and the main function to trap errors** . Also, the database code cannot be copied intact-it is for illustrative purposes only!

#javascript #async/await #programming

How to use async/await to properly link multiple functions in Javascript
67.15 GEEK