require-atomic-updates
禁止由于使用 await
或 yield
而可能导致竞争条件的分配
在编写异步代码时,可能会产生微妙的竞争条件错误。考虑以下示例:
let totalLength = 0;
async function addLengthOfSinglePage(pageNum) {
totalLength += await getPageLength(pageNum);
}
Promise.all([addLengthOfSinglePage(1), addLengthOfSinglePage(2)]).then(() => {
console.log('The combined length of both pages is', totalLength);
});
这段代码看起来将调用 getPageLength(1)
和 getPageLength(2)
的结果相加,但实际上 totalLength
的最终值只是两页之一的长度。错误在语句 totalLength += await getPageLength(pageNum);
中。该语句首先读取 totalLength
的初始值,然后调用 getPageLength(pageNum)
并等待该 Promise 完成。最后,它将 totalLength
的值设置为 await getPageLength(pageNum)
和 totalLength
的初始值之和。如果在 getPageLength(pageNum)
Promise 未决期间在单独的函数调用中更新了 totalLength
变量,则该更新将丢失,因为新值被覆盖而未被读取。
解决此问题的一种方法是确保在更新 totalLength
的同时读取它,如下所示:
async function addLengthOfSinglePage(pageNum) {
const lengthOfThisPage = await getPageLength(pageNum);
totalLength += lengthOfThisPage;
}
另一种解决方案是完全避免使用可变变量引用:
Promise.all([getPageLength(1), getPageLength(2)]).then(pageLengths => {
const totalLength = pageLengths.reduce((accumulator, length) => accumulator + length, 0);
console.log('The combined length of both pages is', totalLength);
});
规则详情
Fgsu6tS5naQ0iqS4FiAK25QEK6egddp2Dt1zUDMT4Xx9K7zv7y+ayK+oLnHDyKk9VDy49LdE7ibNYucrv4tvuqXWavabfcov1nFDdOPxNyieT54M0wtmrs2oGm7LOyad
变量
Zzu48bEO8pzmsDX1nB32Fm2VEsRmY/rDWSk/qOYWNy2dCWi2/26yNA+9l/zF2Wd5jaOmowXtYXuDJJW+hltkQb3c85dSfBZ+g3SAPnA0oNapYwnmi1yWuJ2fio7MmiU5JJYRkItIBTs3pxsl1SsD3A==
- 变量被读取。
yield
或await
暂停该功能。- 函数恢复后,从第 1 步开始为变量赋值。
Loc3SdWEiTZQvAYu/U7EVKbyJs9F8vzWDsOjpUe5eOFJoTRk4V8XpPxB/TipDCKm0SApikoQbeV0herNyLiPCx2Kibj6+z9FOkqScpS4AVDU92BIMrxDk3oqLA+PznVE6wy46C7FXaIbLvf/LJTw5IibCovClv0I4Ov/W4utmsBCwlkRQmY7KXAaW/CmGmh1FOcXQNgpXQFxxyhdWmT7jeD9bWL9jiQsuwbtCI4NsQXrApHjDkT1ktjhEO94EwoRzuH+4xMozJFfVYsccDbiS1cC9Y99GSyWAR2BwdlPMf78jWUPHhRPYrqrbtRNyTzT6kaHhKbO+2wEtDE0GhlmqlHM3nc8Zcm1M/jNn8WrR7MT4WXr9Crdclo4PGEE6JkpJ2GObj7nA8lMRExYbhOehdvkN0h2aMv8JRLeH3q5Ae+/KZskDzCM1o+gtmcUAhiuPLAjzgydkIfvbTcP5Wxh8IO9bOoD8BPy4rsBxFipCFMGDrUTc05qhV9WhXxq+tp3
SxlwUOUGA9V1/uoc8ud3lek81IDSu79WflCB4CQfx7ukqQSfIieK6iwQZg3Kt2NFr9asyIVJsCuGABBzrd5qBVWQpBBi9XGm9gxVcI6VjYQzLs0wQkkuvXxqwCc8NsE3
- 3kg5p0EboyCVrsekgs28qRBUv2oCshjIpoQGY7lNr6dqmyMSa0Ume45GxIbO/n6bchT3OB8LGw1+Gyhw7IlUM/sGRtp51i8n+0nrlGOqU12oZ6x6cZqInNc8hIS6pLDOaW+vrLwWt7hZAYn03t3sta56jT3MQKJYZW6mkp/yEWKfDK0KBaSPoWcjzP4DoPHJTC0Dl81Xrdr0P1PZuH40o4k3s3TCxJlw6Hkx2V6Wh/E=
53qbJC6xNcTpfWzDOxH3FbxQniXPcALMzc0838bz9bxwfaPpKG0ZV7pRGyxgA1aA
/* eslint require-atomic-updates: error */
let result;
async function foo() {
result += await something;
}
async function bar() {
result = result + await something;
}
async function baz() {
result = result + doSomething(await somethingElse);
}
async function qux() {
if (!result) {
result = await initialize();
}
}
function* generator() {
result += yield;
}
x8vS/D2xVZSiiHLs1PwUl6/TVEXV0uticb8dGcMm9rxiwxh8yRqnjwkHP0i+2Pam
/* eslint require-atomic-updates: error */
let result;
async function foobar() {
result = await something + result;
}
async function baz() {
const tmp = doSomething(await somethingElse);
result += tmp;
}
async function qux() {
if (!result) {
const tmp = await initialize();
if (!result) {
result = tmp;
}
}
}
async function quux() {
let localVariable = 0;
localVariable += await something;
}
function* generator() {
result = (yield) + result;
}
属性
Zzu48bEO8pzmsDX1nB32Fm2VEsRmY/rDWSk/qOYWNy2dCWi2/26yNA+9l/zF2Wd5jaOmowXtYXuDJJW+hltkQb3c85dSfBZ+g3SAPnA0oNaricBe0AxpgRuIYHy/h+PyfHpJijLD8fJmF1+n9TyVOMJjT2aAEqjUy6Gg4+p6wAw=
- 读取变量或对象属性。
yield
或await
暂停该功能。- 函数恢复后,将值分配给属性。
Z1CW+AOq8nNRbS1aBT9d0mcZM15PoHIBz0t0VvIpCzpSqgzQDuCBr2Gtx3wcg+/lU4LOXWhsFbZPZtp/qgjJgLkGvXYIvG0hmmbRFpLCCnyP891Y/mY5Ll1KSvwijV1WTfvPEca/I79VfF088MNh7my61gcxrgm63K59KhxP89kVyc39JtH3gU36da9dBf3KWPSrP2ET8FX0VAjn3lCu0Q==
53qbJC6xNcTpfWzDOxH3FbxQniXPcALMzc0838bz9bxwfaPpKG0ZV7pRGyxgA1aA
/* eslint require-atomic-updates: error */
async function foo(obj) {
if (!obj.done) {
obj.something = await getSomething();
}
}
x8vS/D2xVZSiiHLs1PwUl6/TVEXV0uticb8dGcMm9rxiwxh8yRqnjwkHP0i+2Pam
/* eslint require-atomic-updates: error */
async function foo(obj) {
if (!obj.done) {
const tmp = await getSomething();
if (!obj.done) {
obj.something = tmp;
}
}
}
选项
GrNq2fetYiou0eUGLFslKXJzMat3EqRc4rAOvDlDY/Zx340ZWhiXWP+ysh/Dsnow
- SCzwxvbI23WDqfMVnQxdghz1Gu4EWyDMOCpiE66fHWXHUWJWjmcfjI5EOyEVOIClESwqD/4RYUEVS6M0Ft4GyG2uQLkdp79UFQhC6lod+akaIuonwAWPneW8vItOCqL4H9PD7wlmDz1ueU4BHNgJhUbywtbqBTQduBFMVtoaWGDlw9jQ1m7a3K/sxcJrBwfnBi//5JkV2LPW8Zj1BjFG3w==
allowProperties
5nEv4RCYCaBiSjFxJ4F/mM6JUW2lvyiJpQfy7dQT4O6N1AoF1k5fK+C94fIw4Ck6W+ZoAe2AxYi5WtFTaiXKS7ULBL/FJ5MAVcv6126gAtJtMIj4bO31Y2IKZJxJMUaN
/* eslint require-atomic-updates: ["error", { "allowProperties": true }] */
async function foo(obj) {
if (!obj.done) {
obj.something = await getSomething();
}
}
何时不使用
JtS2UXgPMciCMU6s3JF/dCmRYzxv5UI4OW9lwaKr6OdqhqdCkLUDCZsrmfvWPsXRfUtliIimMIB1w/f6/jsGIE6GyVC2NdSvmAL+m41WVYk=