DanLevy.net

别再硬推 async/await 了

Promise 现在可火了

Hero image for 别再硬推 async/await 了

自盘古开天辟地以来,开发者们就一直在进行各种愚蠢的争论。从经典的”制表符 vs. 空格”到永恒的”Mac vs. PC”辩论,我们很擅长寻找分散注意力的论点。


答案: Linux 和 Spaces.

这场争论……?

Promise vs. Async/Await!

等等,这是一场争论吗?肯定是吧?我们似乎不再讨论回调函数了?

不,这不是一场争论。归根结底,它只是你工具箱中的另一个潜在工具。然而,由于 async/await 并未取代 Promise 的所有功能(特别是 Promise.all.race),将其作为替代品来呈现是具有误导性的。

有很多有影响力的人正在推广这种误解,即 async/await 是 Promise 的替代品每个人一直等待

提示:不,绝不,一点也不。

VS Code 最近新增的一个功能进一步助长了这种偏见。正如 @umaar 在推文中所述:

Visual Studio Code 现在可以将你的长串 Promise.then() 链转换为 async/await!🎊 在 JavaScript 和 TypeScript 文件中都运行良好。.catch() 也能正确转换为 try/catch ✅ pic.x.com/xb39Lsp84V

— Umar Hansa (@umaar) 2018年9月28日

如果你讨厌 Promise,并且想要这个重构功能,我不怪你。


我感同身受。我理解。


我也经历过。🤗


我过去讨厌 Promise。如今,我彻底转变了看法。Promise 非常出色。 它们能够促使/鼓励你利用函数组合

我建议先从以下两个方面入手,提升你的 Promise 技巧。

  1. 命名函数(不要匿名)
  2. 单一职责函数

#1:命名函数!

干掉你的匿名方法。使用命名函数能让代码读起来像需求的诗歌。

来看一个常见例子:

使用 fetch 发起 HTTP GET 请求:

反模式

// ❌ 使用匿名内联函数 💩
fetch(url)
.then(response => response.status < 400
? response
: Promise.reject(new Error('Request Failed: ' + response.ststus)))
.then(response => response.text())

解决方案:命名方法

// ✅ 清晰显现:命名函数
fetch(url)
.then(checkResponse)
.then(getText)
// 可复用的通用函数
function checkResponse(response) {
return response.status < 400
? response
: Promise.reject(new Error('Request Failed: ' + response.ststus))
}
function getText(response) {
return response.text()
}

随着代码越来越 DRY,这种方法的优势会愈发明显。

额外资源: 查看我的 1 分钟视频,演示使用此技术的基础日志高级调试

#2:单一职责(函数)

“单一职责”听起来_看似精确_。

但它其实非常主观、随意,甚至有时毫无意义。

让我们看一个例子,这个例子来自(才华横溢的)Jake Archibald 在 Google Developers 网站上关于 async/await 的文章(注意:2024 年,链接已移除)。

// 来源:https://developers.google.com/web/fundamentals/primers/async-functions
function logInOrder(urls) {
// 获取所有 URL
const textPromises = urls.map(url => {
return fetch(url).then(response => response.text());
});
// 按顺序记录它们
textPromises.reduce((chain, textPromise) => {
return chain.then(() => textPromise)
.then(text => console.log(text));
}, Promise.resolve());
}

单一职责?

我认为不是。logInOrder 在做什么?

  1. 遍历 urls 列表
  2. 对每个 URL 执行内联 HTTP GET:
  3. HTTP fetch
  4. 返回响应文本内容
  5. textPromise 中的每个 promise 后追加一个 .then(text => console.log(text))
  6. 串行打印结果

这个单一函数中定义了 5 个匿名方法。正如 Jake 所指出的,.reduce 过于复杂。在代码中到处手写这种精细机制并不合理。换句话说,我们不会用无尽的 document.createElement()element.setAttribute() 等来编写 DOM 创建代码。相反,我们会从众多选项中选择最佳工具:辅助/工具函数、库或框架。

解决方案:单一职责函数

首先提取方法

从 Promise 代码中提取异步方法的 VS Code 重构

接着用 Promise.all..map() 替换 .reduce()logPromise()

使用 Promise.all 和 map 重构 Promise 链以提高可读性

总结

尝试将这些技巧应用到自己的代码中!然后在推特上@我,告诉我效果如何。如果有问题或评论,也欢迎联系我!

帮助传播 #PromiseTruth 并分享本文。❤️

图片来源:matt-nelson-414464-unsplash.webp

相关阅读