【问题标题】:await async - race condition error in ESLint require-atomic-updatesawait async - ESLint require-atomic-updates 中的竞争条件错误
【发布时间】:2021-06-26 04:02:28
【问题描述】:

下面的代码在使用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-atomic-updates 的过时值

【问题讨论】:

  • 能否添加真实代码?
  • @JonasWilms 请在上面查看我的编辑。谢谢
  • 这看起来很像误报。我看不出the rule conditions 如何应用于您的代码。如果这是您的实际代码,我建议您提交错误报告。
  • @Bergi 感谢您查看

标签: javascript async-await eslint race-condition


【解决方案1】:

您可以放心地忽略警告:)

ESLint 是为了捕捉这样的东西:

 let value = 0;

async function race() {
  value += await Promise.resolve(1);
  console.log(value);
}

race(); race();

在这种情况下,race 在堆栈上记忆 valueawaits 一个记号,然后写回value。由于其他代码同时运行,value 可能已被更改,然后更新可能会关闭......它不是原子的。

但是,在您的情况下,您从ctx.request.body 读取并写入ctx.body,因此没有非原子更新。此外,可能没有其他中间件同时访问相同的ctx,因此不能有任何并发​​修改。因此,在您的情况下,这是一个误报,甚至可以怀疑这是否是肯定的(这可能是 ESLint 中的一个错误)。

【讨论】:

【解决方案2】:

我意识到这个答案有点晚了,但对于任何遇到这个问题的未来用户来说,要禁用此规则,在您的 .eslintrc.json 或您使用的任何相关配置中,只需指定:

"require-atomic-updates": "off"

【讨论】:

  • 如果你接受这样的解决方案,为什么你不停止使用 ESLint?这条规则不是文体问题,而是一个预防性错误。就像发生问题时禁用警报一样。
  • 同意。 OP 询问他们如何以不同的方式编写代码,而不是如何清理错误报告。
【解决方案3】:

我不认为这是一个错误。假设您的代码 sn-p 包含在异步函数中,即doRequest

只要在doRequest 之外定义了ctx 变量,ctx.body 赋值就处于竞争状态。因为无法保证分配给ctx.body 的最后一个值属于doRequest 的最后一次调用。

我写了a blog post 关于这个竞争条件。有两种方法可以避免此警告

方法一:将ctx移动到doRequest体中,然后在函数末尾返回ctx值。

方法二:使用promise-base-semaphore pattern

let ctxPromise

每当您发出请求时,请致电ctxPromise = doRequest()

【讨论】:

  • 很好的答案,但不清楚它在上下文中解决这个问题的适用性有多大。这里的代码示例在 Koa 或 Express 等请求/响应 HTTP 处理程序中执行,ctx 是框架提供的托管对象——它不会被重用或从另一个上下文调用。在大多数情况下,赋值表达式是语法糖,因为真正发生的是响应体作为一次性操作被写入输出缓冲区。这种情况下的 Eslint 规则与 Koa API 完全不兼容。
  • @maetl Koa 应用程序或连接中间件开发人员可能会认为这个 ESlint 规则很荒谬。但是,ESlint 也没有足够的信息来确保 Koa 应用程序或连接中间件不会使用 same ctx 参数同时调用相同的中间件。因此,在这种情况下抛出错误是完全有道理的。在编写异步连接中间件时,我也面临同样的问题。我建议的解决方案是 1. 用注释绕过错误。 2.在ESLint设置中将错误改为警告级别
猜你喜欢
  • 1970-01-01
  • 2019-11-25
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-07
  • 2011-07-17
  • 2013-02-27
相关资源
最近更新 更多