async/await与for循环的思考
问题来源
ES6入门教程 看到async函数这一章时,看到如下例子
但是,如果将forEach方法的参数改成async函数,也有问题。
//并发执行
function dbFuc(db) { //这里不需要 async
let docs = [{}, {}, {}];
// 可能得到错误结果
docs.forEach(async function (doc) {
await db.post(doc);
});
}
上面代码可能不会正常工作,原因是这时三个db.post()操作将是并发执行,也就是同时执行,而不是继发执行。正确的写法是采用for循环。
//继发执行
async function dbFuc(db) {
let docs = [{}, {}, {}];
for (let doc of docs) {
await db.post(doc);
}
}
这两个例子一对比,就会感到疑惑,为什么forEach的方式为并发(同步)执行的?而for...of循环就为继发(异步)执行的?
我查阅了MDN关于Async的相关说明,也在网上百度了相关问题,来谈一谈我的理解
我的理解
//并发执行
//写法1
docs.forEach(async function (doc) {
await db.post(doc);
});
//等同于
//写法2
docs.forEach(callback);
async function callback(doc) {
await db.post(doc);
}
因为只有async函数内部是继发执行,外部不受影响。在外部表现async函数整体还是并发的
如上例子callback是个async函数,forEach循环的是并发任务。
//继发执行
async function dbFuc(db) {
let docs = [{}, {}, {}];
for (let doc of docs) {
await db.post(doc);
}
}
for循环的这个例子,根据只有async函数内部是继发执行,外部不受影响。dbFuc是async函数,它内部继发的,所以for循环调用的db.post(doc)就是继发的
实例验证
写两个例子来验证一下我的理解对不对,例子如下:
var resolve1=function (){
return new Promise(resolve=>{
setTimeout(()=>{resolve(new Date())},5000)
})
}
var resolve2=function (){
return new Promise(resolve=>{
setTimeout(()=>{resolve(new Date())},5000)
})
}
并发执行:
console.log(new Date());
var resolve1=function (){
return new Promise(resolve=>{
setTimeout(()=>{resolve(new Date())},5000)
})
};
var resolve2=function (){
return new Promise(resolve=>{
setTimeout(()=>{resolve(new Date())},5000)
})
};
[resolve1,resolve2].forEach(async(item)=>{
let res=await item()
console.log(res)
})
每个异步任务,都是5s后打印当前时间,如果两个任务并发执行,则打印的时间应该相同
打开浏览器->F12->控制台 复制代码 回车 一气呵成
结果如下:
结果显示,两个异步任务是并发执行的
继发执行
console.log(new Date());
var resolve1=function (){
return new Promise(resolve=>{
setTimeout(()=>{resolve(new Date())},5000)
})
};
var resolve2=function (){
return new Promise(resolve=>{
setTimeout(()=>{resolve(new Date())},5000)
})
};
(async function(){
for(let item of [resolve1,resolve2]){
let res=await item()
console.log(res)
}
})()
结果如下:
结果显示,两个异步任务是继发执行的
由运行结果可知,我的理解应该是正确的