我原本以为自己理解了Javascript中async/await
的工作原理,直到我运行了以下代码:
let flag = false;
function test() {
[1, 2, 3].map(async n => {
console.log(`flag set at ${n} before if?`, flag);
if (!flag) {
const x = await a(n);
// do something with x
flag = x;
console.log('flag set!');
}
console.log(`flag set at ${n} after if?`, flag);
});
}
function a(n) {
return new Promise((resolve, reject) => {
setTimeout(function() {
resolve(n);
});
});
}
test();
实际输出结果为:
flag set at 1 before if? false
flag set at 2 before if? false
flag set at 3 before if? false
flag set!
flag set at 1 after if? 1
flag set!
flag set at 2 after if? 2
flag set!
flag set at 3 after if? 3
这与我先前所想的完全不同:
flag set at 1 before if? false
flag set!
flag set at 1 after if? 1
flag set at 2 before if? 1
flag set at 2 after if? 1
flag set at 3 before if? 1
flag set at 3 after if? 1
我觉得我需要接受教育。谢谢。
更新: 感谢评论中提到地图的内容。当我将我的代码更改为以下内容时,它按照预期工作:
let flag = false;
async function test() {
for (const n of [1, 2, 3]) {
console.log(`flag set at ${n} before if?`, flag);
if (!flag) {
const x = await a(n);
// do something with x
flag = x;
console.log('flag set!');
}
console.log(`flag set at ${n} after if?`, flag);
}
}
function a(n) {
return new Promise((resolve, reject) => {
setTimeout(function() {
resolve(n);
});
});
}
test();
map
不会等待,它只是将原始数组转换为一个 Promise 数组,不改变原意且保持通俗易懂。 - zerkmsawait
周围使用for of
。map
只会调用回调函数三次,而每个创建的Promise都是独立的。 - BergisetTimeout
会立即调用回调函数,但它不是同步的,而是有一个最小值-并且它在宏任务循环中,所以肯定会被延迟到所有承诺完成后。 - Bergi