事件循环、回调队列和JavaScript的单线程是如何连接的?

24

总体目标

我想了解以下 JavaScript 环境的组件是如何作为一个系统相互连接的:

  • JavaScript 引擎
  • 事件循环(Event Loop)
  • 事件队列(Event Queue)

我们可以将此限制在 浏览器环境 中,因为 Node 已经在另一篇文章中介绍过 (这里)。

我了解的事情:

  • JavaScript 是单线程的,因此只有一个调用栈。

  • JavaScript 环境仅提供少数几个真正异步的函数。这些函数可能包括 setTimeout()、setInterval() 和 I/O 函数。

  • 开发人员不能创建自己的异步函数,而必须使用其中之一。

  • JavaScript 本身是同步运行的,但通过其异步函数可以在当前调用栈清空后回调原本会阻塞的函数。

示例:

      console.log(‘Sync code started…’);

      setTimeout(function asyncLog() {
           console.log(‘Async function has completed’)
      }, 2000);

      console.log(‘Sync code finished…')

示例步骤:

(如果我有误,请纠正)

  1. 记录“同步代码已启动…”
  2. 将setTimeout添加到堆栈中,但立即返回控件
  3. 将setTimeout发送到不同的“线程”或“工作器”外部,超出JavaScript的单个线程以计算2000毫秒
  4. 记录“同步代码已完成…”
  5. 2000毫秒后,asyncLog()被推送到事件队列中
  6. 因为调用堆栈已清除,事件循环检查待处理回调的事件队列
  7. 事件循环从队列中删除asyncLog()并将其推送到堆栈中
  8. 记录“异步函数已完成”
  9. 现在调用堆栈已清除

问题

如果有人能够总览异步函数(例如setTimeout)从第一次命中调用堆栈到它们被回调到调用堆栈的过程,这些问题就不需要逐个回答。

  1. 第3步中,谁产生了这个新线程?是浏览器吗?
    • 这个新线程被阻塞了对吗?
    • 如果您有一个创建1000个setTimeout的循环,会创建1000个“线程”吗?
    • 一次可以生成多少个线程的限制是什么?
    • 新线程执行完毕后,它如何进入队列?
  2. 谁提供了事件队列?
  3. 谁提供了事件循环?
    • 事件循环是否轮询事件队列?
    • JavaScript的线程是否知道事件循环?还是事件循环只是将事物推到堆栈上?
    • 事件循环如何知道堆栈已清除?
1个回答

14

您的理解和示例似乎基本上是正确的。 现在,回答您的问题:

在第3步中,是谁创建这个新线程? 是浏览器吗?

是的。 它基本上是为那些“真正异步”函数提供实现的东西。 如果我没记错,setTimeout直接在JS引擎中实现,而网络IO肯定是浏览器的责任 - 但是谁创建它们并不重要。 最终,在您的“浏览器环境”中,总是浏览器的某个部分。

这个新线程被阻塞了,对吗?

是的。 不是。 这取决于需要完成的工作,即您调用的哪个异步函数。 有些可能需要旋转新线程,但是对于简单的超时,我非常确定会使用非阻塞系统调用。

如果您有一个循环创建1000个setTimeouts,会创建1000个“线程”吗?

可能。 不过不太可能。 我认为对于那些确实需要自己的线程的异步操作,将使用线程池,并排队请求。 此池的大小可能隐藏在您的浏览器配置的深处。

同时可以生成多少个线程?

这将由操作系统控制。

当新线程完成执行后,它如何进入队列? 谁提供事件队列?

基本上,每个这样的线程的最后一个动作是将其结果放入事件队列中。

谁提供事件循环? 事件循环轮询事件队列吗?

我会说这是实现细节,无论是循环轮询队列还是队列驱动循环迭代。

JavaScript是否知道事件循环? 或者事件循环只是将事物推到堆栈上吗?

我认为 JavaScript 在事件循环线程中运行。事件循环只是不断地从队列中弹出事件并执行它们的 JavaScript。

事件循环如何知道堆栈已清空?

事件循环“调用”JavaScript执行 - 因此当JavaScript返回时,堆栈就清空了。


3
我花了一些时间才意识到这些是对我的问题很好的答案。我觉得一些漂亮的图形展示浏览器如何处理JS引擎会极大地受益于社区。Phillip Roberts关于事件循环的讲解在这些方面也非常有启发性。https://www.youtube.com/watch?v=8aGhZQkoFbQ - kurtcorbett
嗨,我对原帖中关于异步部分“开发人员无法创建自己的异步函数”的问题有疑问,如果您能看一下,将不胜感激:https://stackoverflow.com/questions/53919515/javascript-callback-function-not-executing-as-intended - mzoz
+Bergi非常感谢你,祝你圣诞快乐! - mzoz
MDN有一篇名为[并发模型和事件循环](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop)的文章。 - Dave F

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接