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:
[lint.rules]
"require-atomic-updates" = "error" # or "warn"
Every option, set to its default:
[lint.rules]
"require-atomic-updates" = ["error", {
allowProperties = false,
}]
Examples
Reported:
let total = 0;
async function addPrice(id) {
total += await fetchPrice(id);
}
Not reported:
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:
async function loadUser(session) {
if (!session.user) {
session.user = await fetchUser(session.id);
}
}
Check again after the wait:
async function loadUser(session) {
const user = await fetchUser(session.id);
if (!session.user) {
session.user = user;
}
}
Options
| Option | Default | What it does |
|---|---|---|
allowProperties | false | Don't report assignments to properties. Variables are still checked. |
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.