与ESLINT检查时,下面的代码会导致比赛条件:
let match = false
try {
match = await something()
} catch (err) {
// do something
}
if (match === false) {
// do something
}
编写这个代码块的更好方法是什么?
编辑:
let request = ctx.request.body || {}
let password = request.password
let match = false
try {
match = await bcrypt.compare(password, 'xxxxx')
} catch (err) {
ctx.throw(401, err)
}
if (match === false) {
ctx.throw(401, 'invalid password')
}
ctx.body = {
message: 'logged in ok'
}
ESLINT的错误:
可能的种族条件:
ctx.body
可能会根据一个ctx.body
的过时值require-ratomic-updates
您可以安全地忽略警告:(
Eslint旨在捕捉这样的东西:
let value = 0;
async function race() {
value += await Promise.resolve(1);
console.log(value);
}
race(); race();
在这种情况下,race
在堆栈上记忆value
,await
s tick,然后写回value
。随着其他代码在此期间运行,可以更改value
,然后更新可能关闭...它不是原子。
在您的情况下,您从ctx.request.body
阅读并写入ctx.body
,因此没有非原子更新。另外,可能没有其他中间件同时吸引相同的ctx
,因此不能进行任何并发修改。因此,在您的情况下,这是一个假阳性,甚至可以以任何方式肯定(可能是Eslint中的一个错误(。
我意识到这个答案对此答案有点迟了,但是仅对任何未来的用户遇到此问题,在.eslintrc.json
或您使用的任何相关配置中禁用此规则,只需指定:
"require-atomic-updates": "off"
我认为这不是一个错误。让我们假设您的代码片段包含在异步函数中,即doRequest
。
只要ctx
变量在doRequest
之外定义,ctx.body
分配就处于竞赛状态。因为不可能确保分配给ctx.body
的最后一个值属于doRequest
的最后一个呼叫。
我写了一篇有关这种种族条件的博客文章。有两种避免此警告的方法
方法1:将ctx
移至doRequest
主体,然后在功能末端返回ctx
值。
方法2:使用Promote-Base-semaphore模式
let ctxPromise
每当您启动请求时,请致电ctxPromise = doRequest()
。