为何await在JavaScript类的函数中无法按预期工作?
问题原因分析与解决方案
咱们先拆解一下你遇到的问题:你的代码之所以直接显示3,核心问题在于同步循环和异步操作的执行顺序不匹配。
为什么你的代码会立刻显示3?
- 你的
run方法里虽然有一个异步立即执行函数,但run本身是同步方法——调用v.run(n)时,会马上执行立即函数里的document.body.textContent = n,然后才进入await sleep(1000)的等待。 - 外层的
for循环是同步执行的,四次v.run(n)调用会在瞬间完成:n从0到3快速赋值给textContent,所以页面最后会停在最后一次赋值的3,之后四个sleep才各自开始计时,但这时候页面内容已经不会再变化了。
怎么改成预期的依次计数效果?
关键是要让循环等待前一次的异步操作完成后,再执行下一次。我们需要让run方法返回异步操作的Promise,然后在循环里用await等待每次调用完成。
修正后的代码如下:
const sleep = ms => new Promise(res => setTimeout(res, ms)); class K { // 把run改成async方法,自动返回Promise async run(n) { document.body.textContent = n; await sleep(1000); } } var v = new K(); // 用async立即执行函数包裹循环,才能使用await (async function() { for (let n = 0; n < 4; n++) { await v.run(n); // 等待当前run的异步操作完成,再进入下一次循环 } })();
如果不想修改run的结构,也可以让它返回内部立即执行函数的Promise:
const sleep = ms => new Promise(res => setTimeout(res, ms)); class K { run(n) { // 返回async函数的Promise return (async function() { document.body.textContent = n; await sleep(1000); })(); } } var v = new K(); (async function() { for (let n = 0; n < 4; n++) { await v.run(n); } })();
这样修改后,代码就会依次显示0,等待1秒后显示1,再等1秒显示2,最后等1秒显示3,和你看到的正常示例效果一致。
内容的提问来源于stack exchange,提问作者Phillipp Schwarz
相关产品推荐
相关产品推荐

