小结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 相关文章推荐
Jquery ajax传递复杂参数给WebService的实现代码
Aug 08 Javascript
浅谈Javascript中深复制
Dec 01 Javascript
JavaScript实现iframe自动高度调整和不同主域名跨域
Feb 27 Javascript
JS代码防止SQL注入的方法(超简单)
Apr 12 Javascript
[原创]JavaScript语法高亮插件highlight.js用法详解【附highlight.js本站下载】
Nov 01 Javascript
jQuery实现用户输入自动完成功能
Feb 13 Javascript
微信小程序实现瀑布流布局与无限加载的方法详解
May 12 Javascript
Angular 4依赖注入学习教程之简介(一)
Jun 04 Javascript
es6在react中的应用代码解析
Nov 08 Javascript
Bootstrap-table使用footerFormatter做统计列功能
Sep 07 Javascript
vue中v-for循环给标签属性赋值的方法
Oct 18 Javascript
IDEA配置jQuery, $符号不再显示黄色波浪线的问题
Oct 09 jQuery
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
php中文本数据翻页(留言本翻页)
2006/10/09 PHP
基于wordpress主题制作的具体实现步骤
2013/05/10 PHP
PHP获取POST数据的几种方法汇总
2015/03/03 PHP
php实现将数组转换为XML的方法
2015/03/09 PHP
php排序算法实例分析
2016/10/17 PHP
PHP实现十进制数字与二十六进制字母串相互转换操作示例
2018/08/10 PHP
微信公众平台开发教程②微信端分享功能图文详解
2019/04/10 PHP
PhpStorm 2020.3:新增开箱即用的PHP 8属性(推荐)
2020/10/30 PHP
FileUpload上传图片(图片不变形)
2010/08/05 Javascript
多个js与css文件的合并方法详细说明
2012/12/26 Javascript
九种js弹出对话框的方法总结
2013/03/12 Javascript
jquery实现盒子下拉效果示例代码
2013/09/12 Javascript
jQuery事件处理的特征(事件命名机制)
2016/08/23 Javascript
Vue.js每天必学之内部响应式原理探究
2016/09/07 Javascript
微信小程序 action-sheet底部菜单详解
2016/10/27 Javascript
关于react中组件通信的几种方式详解
2017/12/10 Javascript
浅谈angularJS2中的界面跳转方法
2018/08/31 Javascript
vue中$refs, $emit, $on, $once, $off的使用详解
2019/05/26 Javascript
vue+elementUI实现表格关键字筛选高亮
2020/10/26 Javascript
vue data引入本地图片的两种方式小结
2019/11/13 Javascript
[03:55]2016国际邀请赛中国区预选赛首日TOP10精彩集锦
2016/06/27 DOTA
[47:21]Liquid vs TNC Supermajor 胜者组 BO3 第一场 6.4
2018/06/05 DOTA
详解Python中的正则表达式的用法
2015/04/09 Python
Python urllib、urllib2、httplib抓取网页代码实例
2015/05/09 Python
详解Python编程中time模块的使用
2015/11/20 Python
CSS3属性选择符介绍
2008/10/17 HTML / CSS
HTML5 Web Workers之网站也能多线程的实现
2013/04/24 HTML / CSS
英国时尚饰品和发饰购物网站:Claire’s
2017/07/04 全球购物
EJB的角色和三个对象
2015/12/31 面试题
毕业生的自我评价分享
2013/12/18 职场文书
汽车维修工岗位职责
2014/02/12 职场文书
采购助理岗位职责
2014/02/16 职场文书
课堂教学改革实施方案
2014/03/17 职场文书
四则混合运算教学反思
2016/02/23 职场文书
python 如何在 Matplotlib 中绘制垂直线
2021/04/02 Python
Nginx如何获取自定义请求header头和URL参数详解
2022/07/23 Servers