javascript - 在 Async/Await 下留下无用的同步代码是一种反模式吗?
问题描述
据我了解,正如 Jake Archibald在这里await
解释的那样,背后的重点是“等待”对 promise 的已解决值采取行动,直到它作为微任务遇到。
LLJS 的这段视频显示,async-await 本质上是生成器运行器/解释器函数的语法糖,它产生它等待的位置并将承诺的确定值传递给.next()
方法。这意味着.next()
当等待发生时,运行程序的执行将作为微任务排队。
实际上,其下的所有代码await
只会在下一个微任务检查点执行。如果不需要等待的承诺值的代码位于其下方,这可能是一个问题,这正是异步 IIFE 的问题。
async function ping() {
for (let i = 0; i < 5; i++) {
let result = await Promise.resolve("ping");
console.log(result);
}
console.log("Why am I even here?");
}
async function pong() {
for (let i = 0; i < 5; i++) {
let result = await Promise.resolve("pong");
console.log(result);
}
console.log("I have nothing to do with any of this");
}
console.log("Let the games begin!");
ping();
pong();
console.log("Placeholder for code that is not related to ping pong");
在这个例子中,外部日志首先被记录为运行脚本任务的一部分,然后是已解决的 Promise 的值,按照它们在微任务队列中的排队顺序。在整个过程中,留在 for 循环下面的日志与循环无关,并且会不必要地暂停,直到各自函数体中的最后一个微任务出队列为止。
这正是我们将async
函数用作 IIFE 时发生的情况。如果您有await
用于同步执行的代码,则它必须不必要地等待,直到它上面的所有等待都已从微任务队列中检出。
如果有人盲目地将他们的整个快速路由包装在函数中,我可以看到这是一个问题async
,在那里他们将不必要地await
解决某些承诺,如数据库操作、发送电子邮件、读取文件等......那么为什么人们仍然做这个?
app.post('/forgotPwd', async (req, res) => {
const {email, username} = req.body;
if (!email) {
res.status(400).json({error: "No username entered"});
return;
}
if (!username) {
res.status(400).json({error: "No email entered"});
return;
}
const db = client.db();
const user = await db.collection("Users").findOne({username: username, "userInfo.email": email});
if (!user) {
res.status(400).json({error: "Account not found"});
return;
}
const authToken = await getAuthToken({id: user._id.toHexString()}, "15m");
// Would probably send a more verbose email
await sgMail.send({
from: process.env.EMAIL,
to: email,
subject: 'Forgot Password',
text: `Use this url to reset your password: http://localhost:5000/confirmation/passConf/${authToken}`,
});
res.json({error: ""});
});
解决方案
如果您希望函数中的某些async
内容同步运行,请确保它await
在函数中的第一个之前。
那么为什么人们仍然这样做呢?
对于 SO 来说,这可能是一个离题的问题,因为它在很大程度上需要基于意见的答案,但它可能是 A)因为他们不希望该代码在上面的代码完成之前运行,或者 B)因为他们不懂async
功能。
推荐阅读
- jquery - 在按下 a 标签时加载 href 后执行功能(jQuery)
- ios - 为什么 Button SubView 不会在 swift 4 中回到后面?
- java - 无法获取 eBay OAuth 访问令牌
- c++ - 无法存储(保存)QPainter 图像
- dart - 为什么 CrossAxisAligment 在 Flex、Row 和 Column 中不起作用?
- php - preg_match 允许空白字符串或最多 100 个字符
- python - 从字典中获取值到 JSON 文件中
- ios - 'textFieldDidBeginEditing' 几乎匹配 Swift 中协议'UITextFieldDelegate' 的可选要求'textFieldDidBeginEditing'
- spring - 需要有关 JPA 实体映射的帮助
- java - 如何更新/刷新 TextView 以每秒显示更新的 Json 数据?