require-atomic-updates

Disallow assignments that use a value read before an await or a yield

total += await fetchPrice(id) reads total first, then waits. If two calls run at the same time, both start from the same total, and one of the additions is lost.

The rule checks async functions and generators. It reports an assignment to a variable or a property that was read before an await or a yield and not read again after it. A local variable that no other function uses isn't reported, because nothing else can change it during the wait.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"require-atomic-updates" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"require-atomic-updates" = ["error", {
  allowProperties = false,
}]

Examples#

example.js1 problem
let total = 0;

async function addPrice(id) {
  total += await fetchPrice(id);
}
example.jsNo problems
let total = 0;

async function addPrice(id) {
  const price = await fetchPrice(id);
  total += price;
}

async function sumPrices(ids) {
  let sum = 0;
  for (const id of ids) {
    sum += await fetchPrice(id);
  }
  return sum;
}

A property of a parameter is checked too, because the caller still holds the object:

example.js1 problem
async function loadUser(session) {
  if (!session.user) {
    session.user = await fetchUser(session.id);
  }
}

Check again after the wait:

example.jsNo problems
async function loadUser(session) {
  const user = await fetchUser(session.id);
  if (!session.user) {
    session.user = user;
  }
}

Options#

OptionDefaultWhat it does
allowPropertiesfalseDon't report assignments to properties. Variables are still checked.
example.jswith { "allowProperties": true }No problems
async function loadUser(session) {
  if (!session.user) {
    session.user = await fetchUser(session.id);
  }
}

When not to use it#

The rule can't tell whether two calls ever overlap, so it also reports code where nothing else touches the value. If most reports are about properties of request or context objects, set allowProperties to true.