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

How are the Event Loop, Callback Queue, and Javascript’s single thread connected?

本文关键字:何连接 连接 单线程 回调 队列 事件 Javascript 循环      更新时间:2023-09-26

一般目标

我想知道javascript环境的以下部分如何作为一个系统相互连接

  • Javascript Engine
  • 事件循环
  • 事件队列

我们可以将其限制为浏览器环境,因为节点已在另一篇文章中介绍(此处(

我(相信(理解的事情:

  • 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 被发送到不同的"线程"..."worker"? 在 JavaScript 的单线程之外计算 2000 毫秒
  4. "同步代码已完成..."已记录
  5. 2000 毫秒后,asyncLog(( 被推送到事件队列
  6. 由于调用堆栈已清除,因此事件循环会检查事件队列中是否存在挂起的回调
  7. asyncLog(( 从队列中删除并由事件循环推送到堆栈
  8. 记录"异步功能已完成">
  9. 调用堆栈现已清除

问题

如果有人可以概述异步函数(如 setTimeout(从第一次命中调用堆栈到被回调用堆栈的步骤,则不需要一一回答这些问题。

  1. 在第 3 步中,谁生成此新线程?是浏览器吗?
    • 这个新线程被阻止了,对吗?
    • 如果你有一个创建 1000 个设置超时的循环,会发生什么情况。 是否创建了 1000 个"线程"?
    • 一次可以生成的线程数是否有限制?
    • 当新线程完成执行时,它如何最终出现在队列中?
  2. 谁提供事件队列?
  3. 谁提供事件循环?
      事件
    • 循环是否轮询事件队列?
    • javascript的线程是否知道事件循环? 还是事件循环只是将内容推送到堆栈上?
    • 事件循环如何知道堆栈何时清除?

你的理解和你的例子似乎基本上是正确的。现在,针对您的问题:

在第 3 步中,谁生成此新线程?是浏览器吗?

是的。它基本上是为那些"真正的异步"函数提供实现的东西。IIRC,setTimeout直接在JS引擎中实现,而网络IO肯定是浏览器的责任 - 但谁创建它们并不重要。最后,在您的"浏览器环境"中,它始终是浏览器的一部分。

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

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

如果你有一个创建 1000 个设置超时的循环,会发生什么情况。是否创建了 1000 个"线程"?

可能。不过不太可能。我假设对于那些真正需要自己的线程的异步操作,使用线程池,并且请求排队。此池的大小可能隐藏在浏览器配置的内部。

一次可以生成的线程数是否有限制?

这将由操作系统控制。

当新线程完成执行时,它如何最终出现在队列中?谁提供事件队列?

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

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

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

javascript的线程是否知道事件循环?还是事件循环只是将内容推送到堆栈上?

我会说javascript事件循环线程中运行。事件循环只是重复地从队列中弹出事件并执行它们的 javascript。

事件循环如何知道堆栈何时清除?

事件循环调用 javascript 执行 - 因此当 javascript 返回时堆栈是清晰的。