小结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 相关文章推荐
js克隆对象、数组的常用方法介绍
Sep 26 Javascript
使用js判断TextBox控件值改变然后出发事件
Mar 07 Javascript
如何防止INPUT按回车自动提交表单FORM
Dec 06 Javascript
vue中用H5实现文件上传的方法实例代码
May 27 Javascript
jQuery 控制文本框自动缩小字体填充
Jun 16 jQuery
简单谈谈关于Angular Cli打包的事
Sep 05 Javascript
AngularJS实现动态切换样式的方法分析
Jun 26 Javascript
JS编写兼容IE6,7,8浏览器无缝自动轮播
Oct 12 Javascript
laydate时间日历插件使用方法详解
Nov 14 Javascript
浅谈JS和jQuery的区别
Mar 27 jQuery
深入浅析vue中cross-env的使用
Sep 12 Javascript
Vue 中使用富文本编译器wangEditor3的方法
Sep 26 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
discuz程序的PHP加密函数原理分析
2011/08/05 PHP
[全兼容哦]--实用、简洁、炫酷的页面转入效果loing
2007/05/07 Javascript
网页中CDATA标记的说明
2010/09/12 Javascript
jquery 操作日期、星期、元素的追加的实现代码
2012/02/07 Javascript
JS批量操作CSS属性详细解析
2013/12/16 Javascript
javascript中普通函数的使用介绍
2013/12/19 Javascript
JavaScript实现的一个计算数字步数的算法分享
2014/12/06 Javascript
BootStrap modal模态弹窗使用小结
2016/10/26 Javascript
Google 爬虫如何抓取 JavaScript 的内容
2017/04/07 Javascript
详解webpack 入门总结和实践(按需异步加载,css单独打包,生成多个入口文件)
2017/06/20 Javascript
js轮播图的插件化封装详解
2017/07/17 Javascript
jQuery实现左右滑动的toggle方法
2018/03/03 jQuery
Vue中android4.4不兼容问题的解决方法
2018/09/04 Javascript
nodejs的安装使用与npm的介绍
2019/09/11 NodeJs
Node登录权限验证token验证实现的方法示例
2020/05/25 Javascript
[01:11:10]2014 DOTA2华西杯精英邀请赛 5 24 iG VS VG加赛
2014/05/26 DOTA
有关wxpython pyqt内存占用问题分析
2014/06/09 Python
Python实现的下载8000首儿歌的代码分享
2014/11/21 Python
Python中利用Scipy包的SIFT方法进行图片识别的实例教程
2016/06/03 Python
Python selenium如何设置等待时间
2016/09/15 Python
python中实现将多个print输出合成一个数组
2018/04/19 Python
解决Mac下使用python的坑
2019/08/13 Python
python matplotlib画盒图、子图解决坐标轴标签重叠的问题
2020/01/19 Python
解决更改AUTH_USER_MODEL后出现的问题
2020/05/14 Python
利用PyQt5+Matplotlib 绘制静态/动态图的实现代码
2020/07/13 Python
Python内置函数及功能简介汇总
2020/10/13 Python
如何将anaconda安装配置的mmdetection环境离线拷贝到另一台电脑
2020/10/15 Python
求职自荐信
2013/12/14 职场文书
支教自我鉴定
2014/01/18 职场文书
12月小学生校园广播稿
2014/02/04 职场文书
自强之星事迹材料
2014/05/12 职场文书
群众路线组织生活会发言材料
2014/10/17 职场文书
血轮眼轮回眼特效 html+css
2021/03/31 HTML / CSS
MySQL系列之二 多实例配置
2021/07/02 MySQL
python文件与路径操作神器 pathlib
2022/04/01 Python
Golang Elasticsearches 批量修改查询及发送MQ
2022/04/19 Golang