做者: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