有人可以帮我解释一下这两个的执行过程结果为什么不同吗?

首先是这个睡眠函数async function sleep(ms) {
return new Promise(resolve=>{
        setTimeout(resolve,ms)
    })
}

①:for(let i =0;i<2;i++){
    console.log('s');
    await sleep(1000);
    console.log('e')
}

①的结果为image
可见,每次输出的s和e之间都相差了1秒

②:[1,2].forEach(async i=>{
console.log('s');
await sleep(1000);
console.log('e')
})
并且上面这个同时也可以转换为
for(let i =0;i<2;i++){
(async function (){
console.log('s')
await sleep(1000)
console.log('e')
})()
}
②的结果为image
我的第一个疑问为:想不清楚为什么②会先输出了两个s
我的第二个疑问为:②执行了一次sleep之后这个promise就进入了fufilled状态,但是为什么①的promise可以重新进入pending状态并且再次执行呢?

阅读 1.9k
3 个回答
将两次 for 循环给拆开就能理解了。

在这之前定义一个返回时间的变量

var now = {
  valueOf: (function () { return + new Date(); })
};
async function sleep(ms) {
  return new Promise(resolve => {
    console.log(+now);
    setTimeout(resolve, ms)
  })
}
  • 对于第一个部分
// for (let i = 0; i < 2; i++) {
//   console.log(+now, 's');
//   await sleep(1000);
//   console.log(+now, 'e');
// }

{
  console.log(+now, 's');
  await sleep(1000);
  console.log(+now, 'e');
}
{
  console.log(+now, 's');
  await sleep(1000);
  console.log(+now, 'e');
}

运行的结果:
image.png

可以看出这里的执行时同步执行的,前面的代码块执行完了之后后面的代码块才会执行。可以看做是同一个函数同步往下执行代码。

  • 对于第二个部分
// for (let i = 0; i < 2; i++) {
//   (async function () {
//     console.log(+now, 's')
//     await sleep(1000)
//     console.log(+now, 'e')
//   })()
// }

{
  (async function () {
    console.log(+now, 's')
    await sleep(1000)
    console.log(+now, 'e')
  })()
}
{
  (async function () {
    console.log(+now, 's')
    await sleep(1000)
    console.log(+now, 'e')
  })()
}

运行结果:
image.png

可以看出在这里的两个代码块虽然是同步执行的,但执行的是里面的自执行异步函数,两个自执行函数执行后里面的代码又成为了异步,相互之间并不干扰。

第二个疑问:对于sleep函数来说,函数返回的是一个promise对象,即每次调用这个函数之后都会重新生成一个promise对象,因此①和②里面两次执行的sleep函数都会返回一个新的promise,相互之间是不干扰的,因此不存在再次执行的情况。

已解决:forEach在循环回调callback的时候,在回调函数的外层是没有使用await的,所以无法延迟,但是callback内部是有await,所以起到了延迟效果。
以下为代码:
[1,2].forEach(async i=>{
console.log('s');
await new Promise(res=>{setTimeout(function(){console.log(Math.random());res(1)},i*1000)})
console.log(i)
})
见结果可见,两个promise都起效了,并且await也起了效果

  • 第一个疑问:因为 forEach 中 sleep 并不会阻塞下一次调用回调函数,而 for 中会
  • 第二个疑问:

    ①的promise可以重新进入pending状态

    这是不可能的,可能你观察有误

  • 关于 for 循环种的 await,如何将每次循环分开,有一个 ES9 中的新特性 for await,可以参考 MDN
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题