做者: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 發送結果。主要錯誤是:面試
async function myFunction(){ <your code here> }
聲明自動將整個異步函數的代碼(即 <your code here>
)包裝在 new Promise
中,而後轉換爲 return x
並在代碼中加入 resolve(x)
。 可是你還須要在它以外等待(即 let y = await myFunction()
)或它實際上不會等待。這個調試是很是煩人的。res.send()
的響應,不然函數會認爲它失敗並從新運行它。下面的代碼要作這些事情:數據庫
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()
:它等待這兩個變量( savedToCloud
和 sentEmail
)「到達」(他們的 Promise 已經解決),而後運行 res.send)()
。// 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