是什么让 ES6 中的 `async/await` 语句 运行 顺序 vs 并行?

What makes `async/await` statements run sequentially vs in parallel in ES6?

我已经经历过线程,所以我很清楚Promise.all和多个等待

不过,我对以下两种情况不是很清楚。

为什么案例1是顺序执行(耗时10秒)而案例2是并行执行(耗时4秒)?

案例 1:

function promiseWait(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(true);
    }, time);
  });
}

async function test1() {
  var t0 = performance.now()

  var a = await promiseWait(1000)
  var b = await promiseWait(2000)
  var c = await promiseWait(3000)
  var d = await promiseWait(4000)

  var t1 = performance.now()
  console.log("Call to doSomething took " + (t1 - t0) + " milliseconds."); //takes 10secs
  
}
test1()

案例二:

function promiseWait(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(true);
    }, time);
  });
}

async function test2() {
  var t0 = performance.now()

  const p1 = promiseWait(1000);
  const p2 = promiseWait(2000);
  const p3 = promiseWait(3000);
  const p4 = promiseWait(4000);

  const a = await p1;
  const b = await p2;
  const c = await p3;
  const d = await p4;

  var t1 = performance.now()
  console.log("Call to doSomething took " + (t1 - t0) + " milliseconds.")
}

test2()

在第一种情况下,因为 await 在每次调用 promiseWait 之前,甚至要开始执行对 promiseWait 的下一次调用,它需要等到第一次调用到promiseWait就彻底完蛋了。所以你看到了顺序执行。

在第二种情况下,您在开始等待之前已经调用了 all promiseWait 函数。所以promiseWait已经开始执行了,那你就一个个等待结果吧

在第一种情况下的实现明智,对 setTimeout 的下一次调用必须等到第一个 setTimeout 到期。所以第二个,第三个和第四个定时器需要等到第一个定时器超时并解决承诺才能被调度。

在秒的情况下,您安排一个接一个的 setTimeout 调用,因此计时器 都已经排队 .那你就等着定时器到期,一一兑现你的承诺。

在这种情况下,所有 4 个承诺同时开始。因此它的 setTimeout 计时器在后台并行运行。

计时器有 1 秒的差异,因此如果您在等待之间放置一个控制台日志,您应该每秒看到一个新的控制台日志。

function promiseWait(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(true);
    }, time);
  });
}

async function test2() {
  var t0 = performance.now()

  console.log("putting promises in que");
  const p1 = promiseWait(1000);
  const p2 = promiseWait(2000);
  const p3 = promiseWait(3000);
  const p4 = promiseWait(4000);
  console.log("promises where added to the que");

  const a = await p1;
    console.log("1")
  const b = await p2;
    console.log("2")
  const c = await p3;
    console.log("3")
  const d = await p4;
    console.log("4")
    
  var t1 = performance.now()
  console.log("Call to doSomething took " + (t1 - t0) + " milliseconds.")
}

test2()

可视化看起来像这样:

setTimeout(() => {
   let divs = document.querySelectorAll("div").forEach(div => {
      div.style.setProperty("width", "100%")
   })
},500)
div {
   height: 30px;
   background: red;
   margin: 10px;
   width: 0px;
   transition: width 4s;
   color: white
}
<div style="max-width: 100px";>
Promise 1
</div>
<div style="max-width: 200px";>
Promise 2
</div>
<div style="max-width: 300px";>
Promise 3
</div>
<div style="max-width: 400px";>
Promise 4
</div>

案例1可视化:

let divs = document.querySelectorAll("div")

let delay = (time) => new Promise(res => setTimeout(res, time));

(async() => {
for(let i = 0; i < divs.length; i++) {
   await delay(i + 1000);
   divs[i].style.setProperty("width", "100%");
}
})()
div {
   height: 30px;
   background: red;
   margin: 10px;
   width: 0px;
   transition: width 4s;
   color: white
}
<div style="max-width: 100px";>
Promise 1
</div>
<div style="max-width: 200px";>
Promise 2
</div>
<div style="max-width: 300px";>
Promise 3
</div>
<div style="max-width: 400px";>
Promise 4
</div>

进行更深入的研究...(受 Philip Roberts 启发)。

案例一:SetTimeout一一触发

function promiseWait(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(new Date().toISOString().split('.')[0].replace('T',' '));
    }, time);
  });
}

async function test1() {
  let timeStamp = new Date();
  var t0 = new Date();
  console.log("t0",t0)

  var a = await promiseWait(1000)
  console.log("a",a)
  var b = await promiseWait(2000)
  console.log("b",b)
  var c = await promiseWait(3000)
  console.log("c",c)
  var d = await promiseWait(4000)
  console.log("d",d)
  
  var t1 = new Date();
  console.log("t1",t1)
  console.log("Call to doSomething took " + (t1 - t0) + " milliseconds."); //takes 10secs

}
test1()

控制台:您可以注意到每次超时的总和约为 10 秒。

情况二:SetTimeout同时触发

function promiseWait(time) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(new Date().toISOString().split('.')[0].replace('T',' '));
      }, time);
    });
  }
  
  async function test1() {
    let timeStamp = new Date();
    var t0 = new Date();
    console.log("t0",t0)
  
    const p1 = promiseWait(1000);
    const p2 = promiseWait(2000);
    const p3 = promiseWait(3000);
    const p4 = promiseWait(4000);
    
    console.log("p1",p1);
    console.log("p2",p2);
    console.log("p3",p3);
    console.log("p4",p4);

    const a = await p1;
    console.log("a",a);
    const b = await p2;
    console.log("b",b);
    const c = await p3;
    console.log("c",c);
    const d = await p4;
    console.log("d",d);

    var t1 = new Date();
    console.log("t1",t1)
    console.log("Call to doSomething took " + (t1 - t0) + " milliseconds."); //takes 10secs
  
  }
  test1()

控制台:在这里我们可以注意到计时器一起启动,因此结果为 ~ 4 秒。 (最后一个计时器设置为 4 秒)。