为什么 while 循环会阻塞事件循环?

2024-02-09

Node.js 书中给出了以下示例:

var open = false;

setTimeout(function() {
  open = true
}, 1000)

while (!open) {
  console.log('wait');
}

console.log('open sesame');

作者在解释 while 循环阻止执行的原因时说:

节点永远不会执行超时回调,因为事件循环是 停留在从第 7 行开始的 while 循环上,从不给它机会 处理超时事件!

但是,作者没有解释为什么会在事件循环的上下文中发生这种情况,也没有解释幕后到底发生了什么。

有人可以详细说明一下吗?为什么节点会卡住?以及如何更改上述代码,同时保留while控制结构,以便事件循环不会被阻塞,并且代码将按照人们合理预期的方式运行;等待 之前只会记录 1 秒setTimeout触发,进程在记录“芝麻开门”后退出。

通用解释,例如答案对于这个问题 https://stackoverflow.com/questions/14795145/how-the-single-threaded-non-blocking-io-model-works-in-node-js关于 IO 和事件循环以及回调并不能真正帮助我合理化这一点。我希望直接引用上述代码的答案会有所帮助。


这真的很简单。在内部,node.js 由这种类型的循环组成:

  • 从事件队列中获取一些东西
  • 运行指示的任何任务并运行它直到它返回
  • 当上述任务完成后,从事件队列中获取下一项
  • 运行指示的任何任务并运行它直到它返回
  • 冲洗、起泡、重复——一遍又一遍

如果在某个时刻,事件队列中没有任何内容,则进入睡眠状态,直到事件队列中放入某些内容或直到计时器触发为止。


所以,如果一段 Javascript 位于while()循环,则该任务尚未完成,并且根据上述顺序,在先前的任务完全完成之前,不会从事件队列中选取任何新内容。所以,一个很长或永远的运行while()循环只会破坏工作。因为 Javascript 一次只运行一个任务(JS 执行是单线程的),如果该任务在 while 循环中旋转,那么其他任务就无法执行。

这是一个可能有助于解释它的简单示例:

 var done = false;

 // set a timer for 1 second from now to set done to true
 setTimeout(function() {
      done = true;
 }, 1000);

 // spin wait for the done value to change
 while (!done) { /* do nothing */}

 console.log("finally, the done value changed!");

有些人可能从逻辑上认为 while 循环会一直旋转,直到计时器触发,然后计时器会更改done to true然后 while 循环将完成console.log()最后会执行。那不会发生。这实际上将是一个无限循环console.log()语句永远不会被执行。

问题是一旦你进入旋转等待while()循环,没有其他 JavaScript 可以执行。所以,想要改变值的定时器done变量无法执行。因此,while 循环条件永远不会改变,因此它是一个无限循环。

以下是 JS 引擎内部发生的事情:

  1. done变量初始化为false
  2. setTimeout()从现在开始安排 1 秒的计时器事件
  3. while 循环开始旋转
  4. while 循环旋转 1 秒后,计时器已准备好触发,但在解释器返回事件循环之前它无法实际执行任何操作
  5. while 循环不断旋转,因为done变量永远不会改变。因为它继续旋转,所以 JS 引擎永远不会完成该执行线程,也永远不会从事件队列中提取下一个项目或运行挂起的计时器。

Node.js 是一个事件驱动的环境。为了在实际应用中解决这个问题,done标志会在未来的某些事件中发生变化。所以,而不是旋转while循环中,您将为将来的某些相关事件注册一个事件处理程序并在那里完成您的工作。在绝对最坏的情况下,您可以设置一个循环计时器和“轮询”来经常检查该标志,但几乎在每种情况下,您都可以为将导致以下情况的实际事件注册一个事件处理程序:done标记改变并在这方面做你的工作。正确设计的代码知道其他代码想要知道什么时候发生了变化,甚至可以提供自己的事件侦听器和自己的通知事件,人们可以注册感兴趣的事件,甚至只是一个简单的回调。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 while 循环会阻塞事件循环? 的相关文章

  • 为什么我无法使用 HTML5 音频标签多次播放声音?

    这就是声音的 存储 方式
  • 在 JavaScript 中解析日期时间字符串

    有谁知道如何解析所需格式的日期字符串dd mm yyyy See Mozilla Core JavaScript 参考 日期对象 https developer mozilla org en Core JavaScript 1 5 Refe
  • 如何在D3节点中放置图像?

    到目前为止 我已经创建了这些 D3 节点 用于创建可折叠的层次树 到目前为止 这些节点的颜色为 AA1C1C 深红色 以表明如果您单击它们 它们将扩展到更多节点 我想要做的是在节点中使用图像中的位置 这对于所有用户来说都是一个加号 以知道它
  • 按住鼠标时 JavaScript 重复动作

    是否有一个 JavaScript 函数每隔如此多的毫秒重复一次 以至于按住 html 按钮 如果这可以使用标准 JavaScript 来完成 那就太好了 但使用 jQuery 或 jQuery 插件也很棒 On the mousedown
  • console.log 是如何工作的?

    第一个例子 在以下示例中 http jsfiddle net maniator ScTAW 4 http jsfiddle net maniator ScTAW 4 我有这个js var storage function var store
  • 单击元素外部时触发事件的指令

    我知道有很多问题都在问类似的事情 但没有人真正解决我的问题 我正在尝试构建一个指令 当鼠标单击当前元素外部时 该指令将执行表达式 为什么我需要这个功能 我正在构建一个应用程序 在这个应用程序中 有 3 个下拉菜单 5 个下拉列表 如选择的
  • 代理阻止网络套接字?如何绕行

    我有一个用 Python 编写的正在运行的 websocket 服务器 来自https github com opiate SimpleWebSocketServer https github com opiate SimpleWebSoc
  • 将 JSON 字符串传递给 Django 模板

    我一直在用头撞墙 试图找出为什么我无法将从 Django 模型生成的 JSON 字符串传递到模板的 javascript 静态文件中 事实证明 问题不在模型级别 使用serializers serialize 在脚本本身中放入相同的字符串将
  • 需要将焦点放在react中的div上

    我有一个之前用 H1 标签包裹的文本 页面加载后 我需要专注于该文本 为了方便起见 我将它包装在 div 中 render const translate billing primaryContactSelection true this
  • 如何使 Meteor 上的服务器可以访问文本文件

    我很惊讶我无法在这里搜索我的答案 似乎没有其他人遇到这个问题 当您运行meteor服务时 js html等被打包在 meteor local build文件夹中 但它似乎排除了不是js或html的内容 我有一个名为 magicsets 的文
  • EaselJS Alpha 遮罩滤镜

    我对 Canvas 还很陌生 我一直在尝试将图像颠倒过来EaselJS Alpha 蒙版 http www createjs com demos easeljs alphamaskreveal示例 以便初始图像清晰 并且您可以paint是模
  • 在成功回调之前修改 JSONP 结果

    我想从外部服务加载一些 JSON 数据 然而 它提供 foo bar useful 而我真正关心的是 有用 的部分 我需要将那部分传递给success打回来 我正在尝试使用Deferred一次从多个数据源加载 类似this https st
  • 在 Mobile Safari 中点击

    敲击
  • ExtJS:简单表单忽略 formBind

    我有一个小问题让我发疯了好几天 我有一个表单面板 Ext define EC view PasswordPanel extend Ext form Panel alias widget pwdpanel bodyPadding 15 ini
  • 显示对象内容 - JS/jQuery

    With this data events 返回 object Object 我需要看看里面到底发生了什么 我找到了这个 var Finder each this data events function i n Finder Name i
  • 如何选中表格中输入文本焦点上的复选框

    我试图在输入文本焦点上检查表 DOM 中的复选框 但无法访问复选框元素 但我的焦点正在工作 这是我的 jsfiddle 链接https jsfiddle net 9qha9vft https jsfiddle net 9qha9vft 这是
  • javascript初学者:在javascript中添加动态样式? [复制]

    这个问题在这里已经有答案了 可能的重复 如何使用 Javascript 创建 标签 https stackoverflow com questions 524696 how to create a style tag with javasc
  • Node.js:从 s3 下载文件并将其解压缩为字符串

    我正在编写一个AWS Lambda函数 它需要从AWS S3下载文件 解压缩文件并以字符串形式返回内容 我正在尝试这个 function getObject key var params Bucket my bucket Key key r
  • JavaScript:如何在 Internet Explorer 中模拟更改事件(委托)

    UPDATE 回顾 小提琴和赏金 这个问题并没有引起太多关注 所以我将花一些时间来解决这个问题 我知道我的答案和问题都过于冗长 这就是为什么我继续设置这把小提琴 http jsfiddle net vVA8N 在我看来 这是我目前必须用来接
  • 使用 Javascript 删除字符串的最后一个字符

    我有一个DIV与一些字符 如何在每次单击时删除文本中的最后一个字符DIV itself 删除第一个字符 div on click function this text function index text return text repl

随机推荐

  • 如何将 osx 中的 GCC 从 xcode 移动到 /usr/bin

    我在 Developer usr bin gcc 中有 gcc 编译器 但是当我在终端中输入 gcc 时 它说找不到 我认为这是因为它不在 usr bin 目录中 那么我可以a 将gcc从第一个目录移动到第二个目录 或者设置某种将gcc指向
  • 量角器错误:在 Firefox 上执行“等待 WebDriver 服务器位于 http://127.0.0.1:50636/hub 时超时”

    我在 Firefox 上执行脚本 收到一条 Firefox 升级通知 我将其关闭 再次开始执行 但出现如下错误 Rohits MacBook Pro FFAutomation rohitgathibandhe Users rohitgath
  • 蓝牙 HC-05 发送错误 1F 仅适用于 INQ 命令

    我的新蓝牙 HC 05 模块有问题 在 AT 模式下 它可以与我需要的所有命令完美配合 除了 INQ 我已经尝试事先发送一大堆其他命令 AT INIT OK AT ORGL OK AT ROLE 1 OK AT CLASS 0 OK 他们都
  • 每个版本的 iOS 都附带什么版本的 mobile safari?

    我正在尝试找出可以使用哪些 Javascript API 来实现对 Mobile Safari 到 iOS2 的支持 我还没有在任何地方找到一个列表来显示每个新版本的 iOS 附带的 Mobile Safari 版本 我正在寻找一个可以追溯
  • Laravel,转储自动加载,无需 Shell 访问

    我有两个同名的控制器 app controllers CareersController php 供公众使用 app controllers Admin CareersController php 对于管理员 由于命名冲突 我添加了name
  • 将 String 转换为 Int 并添加特定值

    我有一根绳子ABC0001 我想添加 1对于数据库中的每个新条目 如果我采取SubString 3 myStr Length 3 它只给了我1 修剪所有 0 零 有没有其他方法可以为每个新条目添加 1 Thanks 让我们尝试下面的代码 我
  • python正则表达式获取所有文本直到(,并获取括号内的文本

    我需要两个正则表达式操作的帮助 获取左括号之前的所有文本 e g this is so cool 234 gt this is so cool 获取括号内的文本 即数字 234 直到父级 regex re compile s 在第一组括号内
  • 从 Google App Engine for PHP 加载远程 XML

    我想将第三方服务器的远程动态 XML 文件加载到我的 GAE PHP 应用程序中 itemId 5 uri http www myserver com getInfoItem php itemId itemId format xml 我尝试
  • 如何让atom更像WebStorm IDE?

    所以我喜欢 WebStorm 的一点是它可以在输入 后执行惊人的自动完成功能 我喜欢所有的代码完成和 linting Webstorm 资源消耗很大 而且相当丑陋 对于atom 我不知道如何做到这一点 我可以安装或自定义哪些插件才能使其满足
  • 获取最新的不同记录

    考虑下表 User CreatedDateTime Quantity Jim 2012 09 19 01 00 1 Jim 2012 09 19 02 00 5 Jim 2012 09 19 03 00 2 Bob 2012 09 19 0
  • 如何对谷歌云 git repo 进行代码审查

    我们在谷歌云平台上托管 git repo 我知道对于 github com 我们可以使用拉取请求进行代码审查 但谷歌云似乎没有提供这一点 如何对 Google 云平台上的存储库进行代码审查 一种可能性 我知道并不理想 但仍然有效 是将您的云
  • 适用于 Facebook 可玩广告的 SDK

    我想为 Facebook 平台制作 HTML 可播放广告并在其中显示用户头像 是否可以 根据文档 https developers facebook com docs app ads formats playable ad 可播放广告不得发
  • 如何在 Node Express 中像静态 HTML 页面一样提供渲染的 Jade 页面?

    通常你会在这样的路径中渲染 Jade 页面 app get page function req res next res render page jade 但我想提供所有 Jade 页面 自动呈现 就像提供静态 HTML 一样 app us
  • iOS 线性规划库

    我正在寻找一个 iOS 库 可以为我正在开发的应用程序解决 LP IP BIP MIP 问题 我找到了 GLPK 但不知道如何为 iOS 编译它 在网上搜索了一段时间后 我没有找到任何有趣的东西 如果有人可以帮助我如何编译适用于 iOS 的
  • 使用控制台应用程序 .NET Core 在并行 C# 中运行两个 dotnet 进程

    我有一个包含三个控制台的项目 一个控制台将并行打开其他两个进程来执行某些工作 独立 所有控制台都使用 dotnet core 框架 MultipleConsoleWindows主要应用程序如下所示 static void Main stri
  • 添加组条形图作为绘图中的子图

    我想创建分组 barmode 组 plotly 中的条形图子图 现在的问题是 plotly 不会创建条形图作为痕迹 相反 分组条形图被创建为条形轨迹列表 因此 我不知道如何创建一个包含分组条形图作为子图的图形 即使用添加分组条形图图 app
  • NHibernate HiLo - 所有实体的一张表

    我使用 NHibernate HiLo 作为我的身份生成器 目前 我的数据库中的每个实体表都有一个单独的表 例如 我有 Customer 和 CustomerKey 表 每个表都有一个 NextHiLo 列 如果有一张表能够保存所有其他表的
  • 重叠项目上的单击事件

    I have 带有点击事件的表格行 具有单击事件的按钮 该按钮位于表格行上 我有问题 当我点击按钮时 行单击事件也会执行 但我不希望出现这种行为 我只想单击按钮执行 而不单击行 使用 jQuery 由于问题标签 yourButton cli
  • 带有 mysql 变量的 Mysql 查询在 Zend Framework 1 中不起作用

    Zend 配置是 resources db adapter pdo mysql 得到的查询消息 SQLSTATE HY000 一般错误 db Zend Db Table getDefaultAdapter db gt setFetchMod
  • 为什么 while 循环会阻塞事件循环?

    Node js 书中给出了以下示例 var open false setTimeout function open true 1000 while open console log wait console log open sesame