async与for循环

1,822 阅读2分钟

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)
    }
})()

结果如下:

结果显示,两个异步任务是继发执行的

由运行结果可知,我的理解应该是正确的