文章资料来自

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. 操作系统OS - 线程中的join()为什么叫join

    1. 问题:很好奇为什么叫Join? 参考: https://blog.csdn.net/frankarmstrong/article/details/55504161 https://stackov ...

  2. C/C++网络编程6——实现基于UDP的服务器端/客户端

    通过前面几节的内容,我们已经可以实现基本的C/S结构的程序了,但是当多个客户端同时向服务器端请求服务时,服务器端只能按顺序一个一个的服务,这种情况下,客户端的用户是无法忍受的.所以虚实现并发的服务器端 ...

  3. 数字统计(0)<P2010_1>

    数字统计   (two.pas/c/cpp) [问题描述] 请统计某个给定范围[L, R]的所有整数中,数字 2 出现的次数.  比如给定范围[2, 22],数字 2 在数2中出现了 1次,在数 12 ...

  4. vs2010 c++中内嵌汇编代码

    在研究汇编时,需要自己写点汇编代码测试,用Ollydbg写每次加载程序就没了,不是很方便. 可以考虑直接在程序中写入汇编代码,只需要加上关键字“_asm”宏(C++代码中). 如下示例 编写环境 :v ...

  5. 夯实Java基础(二十二)——Java8新特性之Lambda表达式

    1.前言 Java 8于14年发布到现在已经有5年时间了,经过时间的磨练,毫无疑问,Java 8是继Java 5(发布于2004年)之后的又一个非常最重要的版本.因为Java 8里面出现了非常多新的特 ...

  6. C++获取驱动盘句柄

    转载:https://www.cnblogs.com/sherlock-merlin/p/10792116.html     https://univasity.iteye.com/blog/8052 ...

  7. Spark入门:第4节 Spark程序:1 - 9

    五. Spark角色介绍 Spark是基于内存计算的大数据并行计算框架.因为其基于内存计算,比Hadoop中MapReduce计算框架具有更高的实时性,同时保证了高效容错性和可伸缩性.从2009年诞生 ...

  8. Controller 层类

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

  9. How to recover if NMC cound not connect

    Some times we suddently find that the NMC can not login,. You would see the sybase database error if ...

  10. C 如何判断编译器是否支持C90 C99?

    参考:<C Primer Plus>,Stephen Prata著,姜佑译. ANSI/ISO C标准 美国ANSI成立委员会X3J11,于89/90年,99年,11年,发布C标准:C89 ...