文章资料来自

Node.js 事件循环机制

JS灵魂之问(下)

EventLoop的中国名字叫事件循环,这个玩意真的是高深莫测,一般开发都用不到,代码只管写就行,虽然不用懂,但是面试就是要问,这对我这种小菜鸡真是满满的恶意

先说说异步IO

这个在Linux笔记里有,但是异步IO只有 Linux 下存在,在其他系统中没有异步 IO 支持,那window的异步IO是怎么实现的,利用多线程,我们可以让一个进程进行计算操作,另外一些进行 IO 调用,IO 完成后把信号传给计算的线程,进而执行回调,这不就好了吗?没错,异步 IO 就是使用这样的线程池来实现的,只不过在不同的系统下面表现会有所差异,在 Linux 下可以直接使用线程池来完成,在Window系统下则采用 IOCP 这个系统API(其内部还是用线程池完成的)

上面的三个线程池都加粗了,因为他就是关键字,线程池的运行图很常见

V8、事件循环、事件队列都在单线程中运行,最右侧还有工作线程(Worker Thread)负责提供异步的I/O操作,这就是为什么说Node.js拥有非阻塞的,事件驱动的异步IO架构

不仅是异步IO运行在线程池,NodeJS的计时器,http请求,浏览器的计时器,http请求ajax,ui渲染也都是运行在线程池的,也就是说js是单线程运行是错的,他是同步任务单线程运行,在【Linux/IO】笔记里把NodeJS比作餐厅是最简单的理解,他有个问题是菜做好了通知服务生来拿,IO执行完是不会通知服务生来拿的,正在的通知是线程池里的线程做的,也就是说服务生拿了菜单到厨房后,放了一招【影分身之术】,叫了一个线程在门口等着【上图的观察者】,菜做好了影分身喊了一句菜做好了,然后自己就消失了,这是主线程服务生才知道才做好了

原理代码

/**
* 定义事件队列
* 入队:push()
* 出队:shift()
* 空队列:length == 0
*/
var globalEventQueue = [] /**
* 接收用户请求
* 每一个请求都会进入到该函数
* 传递参数request和response
*/
function processHttpRequest(request,response){ // 定义一个事件对象
var event = createEvent({
params:request.params, // 传递请求参数
result:null, // 存放请求结果
callback:function(){} // 指定回调函数
}); // 在队列的尾部添加该事件
globalEventQueue.push(event);
} /**
* 事件循环主体,主线程择机执行
* 循环遍历事件队列
* 处理非IO任务
* 处理IO任务
* 执行回调,返回给上层
*/
function eventLoop(){
// 如果队列不为空,就继续循环
while(this.globalEventQueue.length > 0){ // 从队列的头部拿出一个事件
var event = this.globalEventQueue.shift(); // 如果是耗时任务
if(isIOTask(event)){
// 从线程池里拿出一个线程
var thread = getThreadFromThreadPool();
// 交给线程处理
thread.handleIOTask(event)
}else {
// 非耗时任务处理后,直接返回结果
var result = handleEvent(event);
// 最终通过回调函数返回给V8,再由V8返回给应用程序
event.callback.call(null,result);
}
}
} /**
* 处理IO任务
* 完成后将事件添加到队列尾部
* 释放线程
*/
function handleIOTask(event){
//当前线程
var curThread = this; // 操作数据库
var optDatabase = function(params,callback){
var result = readDataFromDb(params);
callback.call(null,result)
}; // 执行IO任务
optDatabase(event.params,function(result){
// 返回结果存入事件对象中
event.result = result; // IO完成后,将不再是耗时任务
event.isIOTask = false; // 将该事件重新添加到队列的尾部
this.globalEventQueue.push(event); // 释放当前线程
releaseThread(curThread)
})
}

MicroTask

这个词的中国名字叫微任务,这个概念是跟着Promise一起出现的,百度Promise都会提到他解决了回调地狱

// 之前
fs.readFile('1.json', (err, data) => {
fs.readFile('2.json', (err, data) => {
fs.readFile('3.json', (err, data) => {
fs.readFile('4.json', (err, data) => { });
});
});
}); // 现在
readFilePromise('1.json').then(data => {
return readFilePromise('2.json')
}).then(data => {
return readFilePromise('3.json')
}).then(data => {
return readFilePromise('4.json')
});

Promise确实是解决了回调地狱,但这只是改变了写法,在没有Promise的时代,代码也一样运行,那Promise到底带来了什么,微任务带来了什么,带来了宏任务,233333,上面的EventLoop就是宏任务的运行规则,在没有微任务的时候就是这么循环执行的,但是看上面的模拟运行,异步回调被放在了执行栈数组的最后面,倘若现在的任务队列非常长,那么回调迟迟得不到执行,造成应用卡顿,于是他们开辟了微任务队列,也就是第二个数组

  1. 一开始整段脚本作为第一个宏任务执行
  2. 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
  3. 当前宏任务执行完出队,检查微任务队列,如果有则依次执行,直到微任务队列为空
  4. 执行浏览器 UI 线程的渲染工作
  5. 检查是否有Web worker任务,有则执行
  6. 执行队首新的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空

放到微任务队列怎么理解呢

把下面的代码运行一下,再把注释解开运行一下

正常来说第一次是 1 2 3 4 2.1,因为400ms的计数器,等他回到微任务队列,0ms的计数器都执行完了

正常来说第二次是 1 2 3 ... 2.1 4,当0ms的定时器返回,循环还在继续,循环快完的时候,400ms的定时器也返回了,这时4是在2.1之前的,但是还是2.1比4先输出,因为他插队了,在微任务队列了实现了插队

console.log(1)
new Promise(function(x,y){
console.log(2)
setTimeout(()=>{
console.log(2.1)
},400)
}).then(x=>{
console.log(x)
})
console.log(3)
// for(var i=3;i<10000;i++){
// console.log(i)
// }
setTimeout(()=>{
console.log(4)
})

在浏览器是上面这么执行的,而NodeJS还在循环结束加了个nextTick函数,这是必须在微任务执行队列执行完后执行的,也就是第三个数组,Vue也有一个nextTick是在异步的更新dom后执行的,模仿nodejs的执行概念

就这个理解面试应该没问题了吧,广州有没有招人的,年后想换工作,求收留

EventLoop的更多相关文章

  1. EventLoop和EventLoopGroup

    Netty框架的主要线程就是I/O线程,线程模型设计的好坏,决定了系统的吞吐量.并发性和安全性等架构质量属性.Netty的线程模型被精心地设计,既提升了框架的并发性能,又能在很大程度避免锁,局部实现了 ...

  2. 记录自己对EventLoop和性能问题处理的一点心得

    1.EventLoop 这里说的EventLoop不是指某一个具体的库或是框架,而是指一种程序实现结构.这种结构多是基于IO多路转接的API(select.poll.epoll之类)以reactor模 ...

  3. eventloop & actor模式 & Java线程模型演进 & Netty线程模型 总结

    eventloop的基本概念可以参考:http://www.ruanyifeng.com/blog/2013/10/event_loop.html Eventloop指的是独立于主线程的一条线程,专门 ...

  4. JavaScript EventLoop

    转自:http://cek.io/blog/2015/12/03/event-loop/ What is JavaScript What is JavaScript anyway? Some word ...

  5. QDialog 模态对话框与事件循环(exec其实就是调用了show和eventLoop.exec)

    起源 qtcn中文论坛中有网友问到: 假设程序正常运行时,只有一个简单的窗体A,此时只有一个GUI主线程,在这个主线程中有一个事件循环处理窗体上的事件.当此程序运行到某阶段时,弹出一个模态窗体B(书上 ...

  6. 【Netty】EventLoop和线程模型

    一.前言 在学习了ChannelHandler和ChannelPipeline的有关细节后,接着学习Netty的EventLoop和线程模型. 二.EventLoop和线程模型 2.1. 线程模型 线 ...

  7. [编织消息框架][netty源码分析]2 eventLoop

    eventLoop从命名上看是专门处理事件 事件系统主要由线程池同队列技术组成,有以下几个优点 1.任务出队有序执行,不会出现错乱,当然前提执行线程池只有一个 2.解偶系统复杂度,这是个经典的生产者/ ...

  8. [netty源码分析]3 eventLoop 实现类SingleThreadEventLoop职责与实现

    eventLoop是基于事件系统机制,主要技术由线程池同队列组成,是由生产/消费者模型设计,那么先搞清楚谁是生产者,消费者内容 SingleThreadEventLoop 实现 public abst ...

  9. [编织消息框架][netty源码分析]4 eventLoop 实现类NioEventLoop职责与实现

    NioEventLoop 是jdk nio多路处理实现同修复jdk nio的bug 1.NioEventLoop继承SingleThreadEventLoop 重用单线程处理 2.NioEventLo ...

  10. [编织消息框架][netty源码分析]5 eventLoop 实现类NioEventLoopGroup职责与实现

    分析NioEventLoopGroup最主有两个疑问 1.next work如何分配NioEventLoop 2.boss group 与child group 是如何协作运行的 从EventLoop ...

随机推荐

  1. Apache Shiro安全(权限框架)学习笔记二

    课程目标 通过学习本课程掌握权限管理的设计思想及方法,使用Shiro框架完成权限管理功能开发. 1.  理解基于资源的权限管理方法. 2.  掌握权限管理的数据模型. 3.  掌握不使用shiro开发 ...

  2. Windows 10 20H1版名称被定为Windows 10 Version 2004版以示区分

    导读 我们知道Windows 10 20H1 版目前的开发工作已经接近完成,当前微软主要通过新版本来修复部分已知的问题. 而名称上面按照以往规律推算应该是 Windows 10 Version 200 ...

  3. IIS 应用程序池回收(代码实现)

    回收 public void StartStopRecycleApp(string appName = "项目DLL名称", string method = "Recyc ...

  4. Controller 层类

    package com.thinkgem.jeesite.modules.yudengji.web; import java.util.Date; import javax.servlet.http. ...

  5. Centos7 nginx的负载均衡概念与配置

    一.负载均衡概念 负载均衡(Server Load Balancer)是将访问流量根据转发策略分发到后端多台 ECS 的流量分发控制服务.负载均衡可以通过流量分发扩展应用系统对外的服务能力,通过消除单 ...

  6. C 语言入门---第六章 C语言数组

    数组就是一些列具有相同类型的数据的集合,这些数据在内存中一次挨着存放,彼此之间没有缝隙. 我们可以将二维数组看作一个Excel表格,有行有列,length1 表示行数,length2 表示列数,要在二 ...

  7. 第1节 storm编程:4、storm环境安装以及storm编程模型介绍

    dataSource:数据源,生产数据的东西 spout:接收数据源过来的数据,然后将数据往下游发送 bolt:数据的处理逻辑单元.可以有很多个,基本上每个bolt都处理一部分工作,然后将数据继续往下 ...

  8. Linux命令:history命令历史的管理及用法

    bash可以保存的过去曾经执行过的命令.当某个用户登录到shell中,会读取该用户家目录中的~/.bash_history文件,并将历史命令列表保存到内存中.当用户退出当前shell时,会将内存中的历 ...

  9. 富文本编辑器summernote的基本使用

    summernote比较突出的优点就是能保持复制过来的东西的原有样式,并且比较流畅. 官方文档地址:https://summernote.org/getting-started 我是用到cdn引入 & ...

  10. input 数值框处理

    <input type="text"> input  若设置type=“number” ,再想对其调用处理的函数是不起作用的,为此,首先将其设为文本类型 当前要求是数字 ...