EventLoop
文章资料来自
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就是宏任务的运行规则,在没有微任务的时候就是这么循环执行的,但是看上面的模拟运行,异步回调被放在了执行栈数组的最后面,倘若现在的任务队列非常长,那么回调迟迟得不到执行,造成应用卡顿,于是他们开辟了微任务队列,也就是第二个数组
- 一开始整段脚本作为第一个宏任务执行
- 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列
- 当前宏任务执行完出队,检查微任务队列,如果有则依次执行,直到微任务队列为空
- 执行浏览器 UI 线程的渲染工作
- 检查是否有Web worker任务,有则执行
- 执行队首新的宏任务,回到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的更多相关文章
- EventLoop和EventLoopGroup
Netty框架的主要线程就是I/O线程,线程模型设计的好坏,决定了系统的吞吐量.并发性和安全性等架构质量属性.Netty的线程模型被精心地设计,既提升了框架的并发性能,又能在很大程度避免锁,局部实现了 ...
- 记录自己对EventLoop和性能问题处理的一点心得
1.EventLoop 这里说的EventLoop不是指某一个具体的库或是框架,而是指一种程序实现结构.这种结构多是基于IO多路转接的API(select.poll.epoll之类)以reactor模 ...
- eventloop & actor模式 & Java线程模型演进 & Netty线程模型 总结
eventloop的基本概念可以参考:http://www.ruanyifeng.com/blog/2013/10/event_loop.html Eventloop指的是独立于主线程的一条线程,专门 ...
- JavaScript EventLoop
转自:http://cek.io/blog/2015/12/03/event-loop/ What is JavaScript What is JavaScript anyway? Some word ...
- QDialog 模态对话框与事件循环(exec其实就是调用了show和eventLoop.exec)
起源 qtcn中文论坛中有网友问到: 假设程序正常运行时,只有一个简单的窗体A,此时只有一个GUI主线程,在这个主线程中有一个事件循环处理窗体上的事件.当此程序运行到某阶段时,弹出一个模态窗体B(书上 ...
- 【Netty】EventLoop和线程模型
一.前言 在学习了ChannelHandler和ChannelPipeline的有关细节后,接着学习Netty的EventLoop和线程模型. 二.EventLoop和线程模型 2.1. 线程模型 线 ...
- [编织消息框架][netty源码分析]2 eventLoop
eventLoop从命名上看是专门处理事件 事件系统主要由线程池同队列技术组成,有以下几个优点 1.任务出队有序执行,不会出现错乱,当然前提执行线程池只有一个 2.解偶系统复杂度,这是个经典的生产者/ ...
- [netty源码分析]3 eventLoop 实现类SingleThreadEventLoop职责与实现
eventLoop是基于事件系统机制,主要技术由线程池同队列组成,是由生产/消费者模型设计,那么先搞清楚谁是生产者,消费者内容 SingleThreadEventLoop 实现 public abst ...
- [编织消息框架][netty源码分析]4 eventLoop 实现类NioEventLoop职责与实现
NioEventLoop 是jdk nio多路处理实现同修复jdk nio的bug 1.NioEventLoop继承SingleThreadEventLoop 重用单线程处理 2.NioEventLo ...
- [编织消息框架][netty源码分析]5 eventLoop 实现类NioEventLoopGroup职责与实现
分析NioEventLoopGroup最主有两个疑问 1.next work如何分配NioEventLoop 2.boss group 与child group 是如何协作运行的 从EventLoop ...
随机推荐
- ES5-严格模式
在es5中可以开启一种严格模式的代码形式,开启方式是:将全局或者函数的第一条语句定义为:'use strict';. 如果浏览器不支持,会将其解析为一条普通语句,没有任何的副作用. 开启全局模式后会有 ...
- 四阶幻方-蓝桥杯-DFS
答案:416 用next_permutation()全部排列的话会超时 所以用dfs搜索,只搜索前三行就好,前三行确定之后,第四行也就确定 #include<iostream> #incl ...
- 【剑指Offer面试编程题】题目1356:孩子们的游戏(圆圈中最后剩下的数)--九度OJ
题目描述: 每年六一儿童节,JOBDU都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为JOBDU的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈. ...
- 夯实Java基础(二十四)——Java8新特征之Optional类
1.概述 对于Java程序员来说,到目前为止出现次数最多的应该是NullpointException,它是导致Java应用程序失败的最常见原因.之前处理空指针我们必须先通过条件先去判断,然后再确认是否 ...
- IELTS Simon wr task p3
- elasticsearch 自定义routing
由于线上elasticsearch集群数据量越来越大,优化已经已经是重中之重. 优化的方式有很多中,网上一大堆,自行百度. 优化方案中有个叫routing的方案是个需要熟悉业务日志才能使用.于是我就研 ...
- 网易云信-新增自定义消息(iOS版)
https://www.jianshu.com/p/2bfb1c4e9f21 前言 公司业务需要,PC端,移动端都用到了第三方 网易云信 IM来实现在线客服咨询.在这当中难免遇到一些需求是网易云信没有 ...
- pyhton的返回值
a=input() input()函数返回的是字符‘2’ a=bin(2) bin函数返回的是二进制形式的字符串'0b10' type()判断类型 bin()转化成二进制 int(a,2)可以强制把字 ...
- hdu 2838 Cow Sorting 树状数组求所有比x小的数的个数
Cow Sorting Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- LeetCode刷题笔记和想法(C++)
主要用于记录在LeetCode刷题的过程中学习到的一些思想和自己的想法,希望通过leetcode提升自己的编程素养 :p 高效leetcode刷题小诀窍(这只是目前对我自己而言的小方法,之后会根据自己 ...