用 await/async 正確連接 Javascript 中的多個函數

做者:Dunk

翻譯:瘋狂的技術宅javascript

原文:https://nikodunk.com/how-to-c...前端

未經容許嚴禁轉載java

在我完成 electrade 的工做之餘,還幫助一個朋友的團隊完成了他們的項目。最近,咱們但願爲這個項目構建一個 Craiglist 風格的匿名電子郵件中繼,其中包含 「serverless」 Google Firebase Function(與 AWS Lambda,Azure Function 等相同)。到目前爲止,我發現用 .then() 回調處理異步操做更容易思考,可是我想在這裏用 async/await,由於它讀起來更清晰。我發現大多數關於連接多個函數的文章都沒有用,由於他們傾向於發佈從MSDN 複製粘貼的不完整的演示代碼。在 async/await 上有一些難以調試的陷阱,由於我遇到了全部這些陷阱,因此我將在這裏發佈本身的完整代碼並解釋個人學習過程。程序員

這是鏈接多個函數的工做代碼,等待解決全部問題,而後 then 發送結果。主要錯誤是:面試

  1. 每一個 async function myFunction(){ <your code here> } 聲明自動將整個異步函數的代碼(即 <your code here> )包裝在 new Promise 中,而後轉換爲 return x 並在代碼中加入 resolve(x)可是你還須要在它以外等待(即 let y = await myFunction()或它實際上不會等待。這個調試是很是煩人的。
  2. 在雲函數中,你必須發送帶有 res.send() 的響應,不然函數會認爲它失敗並從新運行它。

下面的代碼要作這些事情:數據庫

  • 咱們有 2 個正常的同步函數 getFieldsFromRequest()extractCourseIdFromEmailAddress() —— 這裏沒問題。
  • 而後咱們須要 async 函數 getEmailOfCourseWithCourseId() 從Firestore獲取課程的電子郵件地址。咱們不知道從 Firestore 獲取內容須要多長時間,所以它是 async 的,咱們須要運行接下來的兩個函數並返回(或以 promise 解析)courseEmail
  • 接下來的兩個函數 saveToCloudFirestore()sendEmailInSendgrid(),不能在 getEmailOfCourseWithCourseId() 以前運行並返回 courseEmail,不然它們將認爲 courseEmail 未定義,這樣的話一切都變得糟透了。 經過 awaiting 上面的函數 getEmailOfCourseWithCourseId() 並傳遞 courseEmail,這些函數(以及 if 運算符)將等到這種狀況發生(也就是說已經解決),而後運再行。
  • 最後,在運行 saveToCloudFirestore()sendEmailInSendgrid() 並返回它們的值以前,不能發送 res.send(),不然咱們的整個雲函數將在工做完成以前中斷。爲此,咱們將 saveToCloudFireStore()sendEmailInSendgrid() 響應(它們返回的內容)保存到變量中,其惟一目的是標記上述函數什麼時候完成。這在某種意義上取代了 .then():它等待這兩個變量( savedToCloudsentEmail)「到達」(他們的 Promise 已經解決),而後運行 res.send)()
  • 爲了便於閱讀,我已經刪除了你應該在實踐中進行的 try/catch 包裝。你永遠不該該捕獲錯誤,但刪除它們會使 async/await 概念更容易理解。
// 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;
}

最後try {}catch {} 包裝最後3個異步函數和主函數來捕獲錯誤。此外,數據庫代碼不能原封不動的複製 —— 它僅用於說明目的!segmentfault


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索