【问题标题】:What makes `async/await` statements run sequentially vs in parallel in ES6?是什么让 `async/await` 语句在 ES6 中顺序运行而不是并行运行?
【发布时间】:2021-01-27 10:00:19
【问题描述】:

我已经通过线程Any difference between await Promise.all() and multiple await?,所以我很清楚 Promise.all 和多个等待。

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

为什么在案例 1 中它是顺序执行(需要 10 秒)而在案例 2 中它是并行执行(需要 4 秒)?

案例一:

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

案例 2:

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

【问题讨论】:

  • 因为 1) 在每个 await 中,在执行下一个语句之前等待承诺解决 - 在 2) 您开始承诺而不等待前一个解决 - 所以它们并行运行跨度>
  • 因为它实际上确实......在这些等待之间......如果你不相信我的话,放一些 console.logs......他们会在每个承诺解决时间隔 1 秒输出/跨度>
  • .allSettled 就像 .all - 但从不拒绝,总是被解决 - 结果显示单独的解决/拒绝状态......而对于 .all,一个拒绝拒绝 .all
  • Promise 底层支持(例如 XHR 请求)“并行”运行时“并行”完成(实际上,有一个限制,例如 6 个请求/域)。并发!= 并行。
  • 如果您知道Promise.all 为何/如何工作,那么您应该知道它是如何工作的。它非常相似。如果您执行await Promise.all([foo(), bar(), baz()]),那么您正在调用foobarbazfirst(即启动所有承诺)并将它们的返回值传递给Promise.all。它与var p1 = foo(); var p2 = bar(); var p3 = baz(); await Promise.all([p1,p2,p3]) 相同,而后者又与var p1 = foo(); var p2 = bar(); var p3 = baz(); await p1; await p2; await p3;“相似”(不完全相同)。

标签: javascript ecmascript-6 async-await es6-promise


【解决方案1】:

进行更深入的研究......(受菲利普·罗伯茨的启发)。

案例一: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 秒。

案例 2: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 秒)。

【讨论】:

    【解决方案2】:

    在这种情况下,所有 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>

    【讨论】:

      【解决方案3】:

      在第一种情况下,由于在每次调用 promiseWait 之前都有 await,甚至开始执行对 promiseWait 的下一次调用它需要等到对 promiseWait 的第一次调用完全完成.所以你会看到顺序执行。

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

      在第一种情况下明智地实施,对setTimeout 的下一次调用必须等到第一个setTimeout 过期。所以第二个、第三个和第四个定时器需要等到第一个定时器过期并解析promise才能被调度。

      在秒的情况下,您将一个接一个地安排setTimeout 调用,因此计时器都已排队。然后你只是在等待计时器到期并一一解决你的承诺。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-08-08
        • 2018-06-25
        • 2018-11-06
        • 1970-01-01
        • 1970-01-01
        • 2019-10-15
        • 2017-06-28
        相关资源
        最近更新 更多