【问题标题】:JavaScript Async/Await logic behaving as synchronousJavaScript Async/Await 逻辑表现为同步
【发布时间】:2020-09-20 20:39:14
【问题描述】:

如果我理解正确,使用关键字 async 声明的函数应该返回一个承诺。在 async3 函数的情况下,我们有 10 亿次迭代,这使得返回值需要更长的时间。分析下面的代码,我预计会发生的是,通过调用 sync1sync2 函数,立即登录控制台,稍后会出现 async3 函数日志.但是,我注意到 sync1sync2 函数仅在 async3 结束后才记录。 async3 函数是否应该在另一个线程上或事件循环之外运行而不会阻塞在运行时调用的其他函数的执行?

function sync1() {
  console.log(1);
}

function sync2() {
  console.log(2);
}

async function async3() {
  let iteration = 0;
  let number = 0;
  while (iteration <= 1000000000) {
    number = iteration;
    iteration++;
  }
  return number;
}

sync1();
sync2();
async3().then((val) => console.log(val));

你能解释一下它为什么会这样吗?我错过了什么?

我的预期:

sync1(); // console logged immediately
sync2(); // console logged immediately
async3().then((val) => console.log(val)); // console logged moments later

目前正在发生的事情:

同步1(); // async3 完成后记录控制台 同步2(); // async3 完成后记录控制台 async3().then((val) => console.log(val)); // async3 完成后记录控制台

【问题讨论】:

  • 你在 async3 中的代码是完全同步的。 Nodejs 在单个线程中运行该 Javascript,因此在同步循环完成之前它不能运行其他任何东西。 async 关键字不会使同步代码突然变为异步。您的 async3 函数同步运行您的循环,然后返回一个已履行的承诺。
  • 另外,console.log() 有自己的问题,即它何时显示某些内容。直观地看到日志语句何时显示并不代表真正的代码流。它应该代表正确的顺序,但不一定代表正确的时间。

标签: javascript async-await es6-promise


【解决方案1】:

请记住,JavaScript 基本上是单线程的。

虽然async3 是异步的,但它的操作完全同步,并且占用大量 CPU。只有当浏览器有一点空闲时间时,输出才会(视觉上)打印到控制台,但是下面的代码块:

  while (iteration <= 1000000000) {
    number = iteration;
    iteration++;
  }

在上述计算完成之前让浏览器没有空闲时间。

为了让sync1sync2 立即登录,一种解决方案是让async3 每100,000 次迭代(或其他)暂停一次,并等待setTimeout,从而让浏览器有机会执行类似的操作向控制台显示内容、处理其他事件侦听器、渲染更改等等。

另一种解决方案是在 worker 中执行计算繁重的 async3 函数,该函数位于单独的线程上,不会阻塞浏览器的主线程。

【讨论】:

  • 他能否将 while 操作包装在另一个函数中并等待那个 await ()=&gt; { while ... return result},或者这对 while 之类的迭代过程没有影响?
  • 这不会有任何影响,因为while 仍然不会从主线程中退出。只有在函数的同步组件完成遇到await时才会产生控制流。
  • CPU 太忙是不对的。这是 JS 处理浏览器事件的方式。 setTimeout、setInterval、console.log 等都在逻辑在堆栈上的队列中结束。堆栈为空后(调用所有函数,脚本完成)队列将被处理。这就是您在“同一”时间看到所有消息的原因。请参阅文档:developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
  • @CertainPerformance 让我检查一下我是否明白这一点。您是说只要在客户端进行计算,之后它就会一直阻止脚本的执行?我在哪里可以找到更多关于那个工人(你提到的)到一个单独的线程?
  • @joaogeraldes 如果计算是在没有在中间显式异步的(如awaitsetTimeout),那么它将完全阻塞任何其他JS执行,以及事件处理程序、滚动、(可见)日志记录等,直到计算完成。对于 Web Worker,请参阅 MDN:developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-10
  • 2017-10-26
相关资源
最近更新 更多