为什么 ESLint no-await-in-loop 不能与 for await of 一起使用?

Why ESLint no-await-in-loop not working with for await of?

for await of — 应该与异步迭代器一起使用,它等待迭代器中的每个承诺并处理其主体中每个等待的承诺的响应。从 MDN 文档中,此语法也可用于同步迭代器,因此

我有以下类似的代码示例:

(async () => {
    const entityIds = [1, 2, 3, 4];
    
    for await (const id of entityIds) {
        console.log(await getEntityById(id));
    }
})();

并且:

(async () => {
    const entityIds = [1, 2, 3, 4];
    
    for (const id of entityIds) {
        console.log(await getEntityById(id)); // ESLint: Unexpected `await` inside a loop.(no-await-in-loop)
    }
})();

但在第二个示例中,我收到了关于规则 no-await-in-loopeslint 警告。问题是:为什么?这 2 个循环的每次迭代都将等待异步函数完成,但 eslint 根本不会对第一种情况做出反应。

no-await-in-loop rule in ESLint 应该可以保护您免受意外 顺序处理某些数据。原因是经常在循环中使用 await 并不是故意的,因为并行处理数据效率更高。因此,当规则打开时,循环中所有 await 的使用都被视为“错误”。

使用 for await...of 明确地 被规则视为“故意”。检查规则的测试(文档页面底部),以下部分被列为有效代码:

valid: [
    // ...

    // Asynchronous iteration intentionally
    "async function foo() { for await (var x of xs) { await f(x) } }"
],

而在任何其他循环结构中使用 await 都是无效的。包括在 for await...of:

的循环中使用 await
invalid: [
    // ...

    // In a nested loop of for-await-of
    { code: "async function foo() { for await (var x of xs) { while (1) await f(x) } }", errors: [error] }
]

最有可能的原因是使用 for await...of 您选择了顺序处理。如果您处理一个异步可迭代对象,那么您无法并行执行该操作的可能性非常高,如果您尝试这样做将会出错。如果您正在处理产生承诺的同步迭代,您仍然有可能无法正确地并行执行此操作。

ESLint 实际上无法检测到您是否有一个像数组迭代器一样产生同步结果的同步迭代器,因此,它假定它是前两个选项之一。


在我看来,这条规则是有缺陷的,因为它是全有或全无。启用它意味着您不希望其中包含 await 的循环。在某些有效情况下,您希望在内部使用 for...ofawait 进行顺序处理。这意味着你的代码很可能在你不需要的时候被 弄得乱七八糟。

我的建议是禁用 no-await-in-loop 规则,并在使用顺序处理和使用并行处理时运用常识。