在我完成 electrade【https://www.electrade.app/】 的工作之余,还帮助一个朋友的团队完成了他们的项目。最近,我们希望为这个项目构建一个 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():它等待这两个变量( savedToCloud 和 sentEmail)“到达”(他们的 Promise 已经解决),然后运行 res.send)() 。

  • 为了便于阅读,我已经删除了你应该在实践中进行的 try/catch 包装。你永远不应该捕获错误,但删除它们会使 async/await 概念更容易理解。
 1// this is the cloud function you can call over HTTP. It is basically for email relay: 2// it gets an email from sendgrid, parses the fields, looks up the real email with the courseId, 3// saves to FireStore and sends and email with sendgrid. 4// Finally, it sends a res.send() to end the cloud function 5 6// {* import a bunch of shit *} 7 8// main function 9exports.emailFunction = functions.https.onRequest(async (req, res) => {10  let fields = getFieldsFromRequest(req); // sync11  let courseId = extractCourseIdFromEmailAddress(fields); // sync12  let courseEmail = await getEmailOfCourseWithCourseId(courseId); // async13  let savedToCloud = await saveToCloudFirestore(fields, courseEmail, courseId); // async14  let sentEmail = await sendEmailWithSendgrid(fields, courseEmail);  // async15  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. 16});1718// Helper functions below19function getFieldsFromRequest(req) { // sync20    let fields = readTheFieldsFromReqWithBusboy(req)21    return fields;22}2324function extractCourseIdFromEmailAddress(fields) { // sync25    let courseId = fields.to.substring(0, fields.to.indexOf('@'));26    return courseId;27}2829async function getEmailOfCourseWithCourseId(courseId) { // async important30    let courseData = await database.get(courseId)31    let courseEmail = courseData.email;32    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)'33}3435async function sendEmailWithSendgrid(fields, courseEmail) { // async important36    let msg = {to: courseEmail, from: fields.from, text: fields.text}37    let sentEmail = await sendgrid.send(msg)38    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)'39}4041async function saveToCloudFirestore(fields, courseEmail, courseId) { // async important42    let savedToCloud = await database.add(fields, courseEmail, courseId)43    return savedToCloud;44}

最后用 try {}catch {} 包装最后3个异步函数和主函数来捕获错误。此外,数据库代码不能原封不动的复制 —— 它仅用于说明目的!
原文:https://nikodunk.com/how-to-chain-functions-with-await-async/

©著作权归作者所有:来自51CTO博客作者mb5ff980b461ced的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 写了一个 SSO 单点登录的代码示例给胖友!
  2. 37000 字 + 代码,艿艿肝的 Shiro 从入门到实战,直接收藏吃灰!
  3. 44000 字 + 代码,艿艿肝的 Spring Security 从入门到实战,直接收藏
  4. Spring 异步调用,一行代码实现!舒服,不接受任何反驳~
  5. Spring Boot项目利用MyBatis Generator进行数据层代码自动生成
  6. 【第562期】用 webpack 构建 node 后端代码,使其支持 js 新特性并
  7. 怎样编写更好的 JavaScript 代码[每日前端夜话0xA4]
  8. 用原生 JavaScript 实现十大 jQuery 函数[每日前端夜话0x94]
  9. 芋道 Spring Boot 消除冗余代码 Lombok 入门

随机推荐

  1. LinearLayout中gravity和layout_gravity
  2. Android应用程序基础
  3. Android(安卓)二级列表
  4. Android CTS 测试总结【转】
  5. Android之 UI主线程
  6. Android 在界面中显示以及输入文本信息 T
  7. android ListView控件 去上下滑动阴影 选
  8. android udp通信
  9. 【android】关于退出时关闭“后台”显示
  10. Ubuntu 系统上编译Android 系统