在过去的 JavaScript 版本中,如果在循环中使用了 async 函数和 await 关键字,可能会导致意外的行为。因为 await 关键字只能在 async 函数内部使用,而循环中的每一次迭代都是一个新的函数调用,所以 await 关键字在循环中可能会访问到错误的变量。这个问题在 ES8 中得到了修复。
修复前的问题
考虑以下示例代码:
// javascriptcn.com 代码示例 async function example() { const promises = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]; const results = []; for (const promise of promises) { const result = await promise; results.push(result); } console.log(results); // [1, 2, 3] }
这段代码看起来很正常,它会等待每个 Promise 完成,然后将结果存储在数组中。但是,如果我们稍微修改一下代码:
// javascriptcn.com 代码示例 async function example() { const promises = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]; const results = []; for (const promise of promises) { setTimeout(async () => { const result = await promise; results.push(result); }, 0); } console.log(results); // [] }
现在,我们将 await 放在了一个 setTimeout 中。由于 setTimeout 是异步的,所以它会在循环结束之后才执行。但是,在这个时候,await 关键字已经访问了错误的变量,因为每次迭代都是一个新的函数调用。因此,我们得到了一个空的结果数组。
修复后的解决方案
ES8 修复了这个问题,使得 await 关键字在循环中的作用域正确地限制在每个循环迭代中。这个修复是通过将循环中的每个迭代都转换为一个单独的函数调用来实现的。
考虑以下示例代码:
async function example() { const promises = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]; const results = []; for await (const promise of promises) { results.push(promise); } console.log(results); // [1, 2, 3] }
现在,我们使用了 for await 循环,而不是 for 循环。这个循环会将每个迭代都转换为一个单独的函数调用,使得 await 关键字在循环中的作用域正确地限制在每个循环迭代中。这样,我们就可以安全地在循环中使用 await 关键字了。
总结
ES8 修复了循环访问的 await 范围的问题,使得在循环中使用 async 函数和 await 关键字变得更加安全和可靠。使用 for await 循环可以避免在循环中出现意外的行为。在编写 JavaScript 代码时,我们应该始终注意这个问题,并尽可能地使用最新的语言特性来避免这种问题的发生。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/655d8dedd2f5e1655d7d2d03