小结Node.js中非阻塞IO和事件循环


Posted in Javascript onSeptember 18, 2014

学习和使用Node.js已经有两个月,使用express结合mongoose写了一个web应用和一套RESTful web api,回过头来看Node.js官网首页对Node.js的介绍:Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.那么其中的non-blocking I/O model 意味着什么呢?

非阻塞的IO模型

首先,IO操作无疑是耗时的,当服务器端接收到大量请求时,为每一个请求创建进程或线程的同时,也增加了额外的内存开销,也可能浪费更多的时间资源。

由于Node.js是事件驱动的,于是它使用了事件循环来解决IO操作带来的瓶颈问题。在Node.js中,一个IO操作通常会带有一个回调函数,当IO操作完成并返回时,就会调用这个回调函数,而主线程则继续执行接下来的代码。简单的用一个例子来说明这个问题:

request('http://www.google.com', function(error, response, body) {
   console.log(body);
});
 
console.log('Done!');

这段代码的意思是向'http://www.google.com'发出请求,当请求返回这则调用回调函数输出响应信息。由于Node.js的运行机制,这段代码运行后,会立即在控制台输出'Done!',然后一段时间后再输出响应的信息。

事件循环 event loop

接下来,来讨论下事件循环的机制。首先说说调用?C,比如有如下一段代码:

function A(arg, func){
  var a = arg;
 
  func();
  console.log('A');  
}
 
function B(){
  console.log('B');
}
 
A(0, B);

当代码执行后,函数A首先被推入调用?C中成为栈顶元素并开始执行A,在执行过程中函数B又被推入调用?C成为栈顶元素,在B执行完成后,B被弹出调用?C,A再次成为栈顶元素,在A执行完成后A被弹出调用?C,调用?C呈空闲状态。

在Javascript运行时中存在一个消息队列,而消息和一个回调函数相关联,当一个事件被触发时,如果这个事件有相应的回调函数,则该消息就会被加入到消息队列中去。

回过头来说事件循环到底循环的是什么,在代码开始执行后,函数被不断推入调用?C中,就拿上面的例子来讲,request被推入调用?C中,这个函数将进行一个http请求(这个http请求将交由Node.js的底层模块来实现)同时请求完成的事件和一个回调函数关联起来,request被弹出调用?C,console.log被推入调用?C开始执行。当请求完成时,完成事件被触发,一条消息被添加进消息队列中,消息队列首先会检查调用?C是否为空闲状态,如果调用?C并不空闲,则会一直等待到调用?C空闲状态后,将消息队列的头部弹出,此时与该消息相关联的回调函数被执行。

小结

以上就无阻塞模型和事件循环在概念上进行了总结。而这个事件循环的机制并不仅仅是Node.js所独有的,并且Node.js的代码是单线程执行的,在面对大量并发请求的时候,又有着什么优势呢?

小结Node.js中非阻塞IO和事件循环

上面这张图展示了Node.js的架构图,Node.js的底层有一个模块负责维护线程池,当一个IO请求发出的时候,Node.js的底层模块将新建一个线程来处理请求,完成后再将结果交还给上层。那么,当有多个请求的时候,Node.js的底层模块将利用尽可能少的线程来完成最多的任务,如果存在空闲的线程,它将继续被利用来做其他的事情,这对于前面说的针对每个请求开一个新的进程或线程而言,无疑“聪明”许多,也更加高效了。

这篇文章是对学习Node.js的一个总结,其中若有问题和不足,欢迎批评指正。

Javascript 相关文章推荐
Javascript 篱式条件判断
Aug 22 Javascript
jQuery 可以拖动的div实现代码 脚本之家修正版
Jun 26 Javascript
Extjs TriggerField在弹出窗口显示不出问题的解决方法
Jan 08 Javascript
JavaScript通过元素的ID和name设置样式
Jul 08 Javascript
js验证真实姓名与身份证号,手机号的简单实例
Jul 18 Javascript
D3.js封装文本实现自动换行和旋转平移等功能
Oct 14 Javascript
在Vue methods中调用filters里的过滤器实例
Aug 30 Javascript
vue单页面实现当前页面刷新或跳转时提示保存
Nov 02 Javascript
js中实例与对象的区别讲解
Jan 21 Javascript
浅谈javascript中的prototype和__proto__的理解
Apr 07 Javascript
vue.js中使用echarts实现数据动态刷新功能
Apr 16 Javascript
在layui.use 中自定义 function 的正确方法
Sep 16 Javascript
JavaScript将取代AppleScript?
Sep 18 #Javascript
Javascript MVC框架Backbone.js详解
Sep 18 #Javascript
JS回调函数的应用简单实例
Sep 17 #Javascript
js实现在同一窗口浏览图片
Sep 17 #Javascript
js实现获取焦点后光标在字符串后
Sep 17 #Javascript
在JavaScript中构建ArrayList示例代码
Sep 17 #Javascript
取得元素的左和上偏移量的方法
Sep 17 #Javascript
You might like
jq的get传参数在utf-8中乱码问题的解决php版
2008/07/23 PHP
按上下级层次关系输出内容的PHP代码
2010/07/17 PHP
php实现通用的从数据库表读取数据到数组的函数实例
2015/03/21 PHP
php将HTML表格每行每列转为数组实现采集表格数据的方法
2015/04/03 PHP
Laravel下生成验证码的类
2017/11/15 PHP
Javascript实现滑块滑动改变值的实现代码
2013/04/12 Javascript
使用jquery实现div的tab切换实例代码
2013/05/27 Javascript
jQuery表格插件ParamQuery简单使用方法示例
2013/12/05 Javascript
js兼容火狐获取图片宽和高的方法
2015/05/21 Javascript
seajs学习教程之基础篇
2016/10/20 Javascript
关于Sequelize连接查询时inlude中model和association的区别详解
2017/02/27 Javascript
vue select选择框数据变化监听方法
2018/08/24 Javascript
Vue条件循环判断+计算属性+绑定样式v-bind的实例
2018/09/18 Javascript
微信运维交互机器人的示例代码
2018/11/12 Javascript
vue使用prop可以渲染但是打印台报错的解决方式
2019/11/13 Javascript
react-router-dom 嵌套路由的实现
2020/05/02 Javascript
解决vue.js中settimeout遇到的问题(时间参数短效果不稳定)
2020/07/21 Javascript
[01:18:36]LGD vs VP Supermajor 败者组决赛 BO3 第一场 6.10
2018/07/04 DOTA
python使用多线程不断刷新网页的方法
2015/03/31 Python
Python随手笔记第一篇(2)之初识列表和元组
2016/01/23 Python
python3实现暴力穷举博客园密码
2016/06/19 Python
python生成器与迭代器详解
2019/01/01 Python
python getopt模块使用实例解析
2019/12/18 Python
基于python实现文件加密功能
2020/01/06 Python
Python对象的属性访问过程详解
2020/03/05 Python
Sandro Paris美国官网:典雅别致的法国时尚服饰品牌
2017/12/26 全球购物
Tirendo比利时:在线购买轮胎
2018/10/22 全球购物
欧洲最大的预定车位市场:JustPark
2020/01/06 全球购物
会计工作心得体会
2014/01/13 职场文书
总经理岗位职责描述
2014/02/08 职场文书
村主任“四风”问题个人整改措施
2014/10/04 职场文书
党的群众路线教育实践活动个人剖析材料
2014/10/07 职场文书
中学教师教学工作总结
2015/08/13 职场文书
MySQL注入基础练习
2021/05/30 MySQL
SQL Server作业失败:无法确定所有者是否有服务器访问权限的解决方法
2021/06/30 SQL Server
AJAX实现指定部分页面刷新效果
2021/10/16 Javascript