文章资料来自

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. RuntimeError: cuda runtime error (10) : invalid device ordinal

    This is caused by the unmatching of gpu device number when loading a saved model. torch.load('my_fil ...

  2. MSSQL2005数据库快照(SNAPSHOT)初探

    定义:数据库快照是数据库(称为“源数据库”)的只读静态视图.在创建时,每个数据库快照在事务上都与源数据库一致.多个快照可以位于一个源数据库中,并且可以作为数据库始终驻留在同一服务器实例上.在创建数据库 ...

  3. Java-用星号打印菱形

    打印如图所示菱形9行9列(提示可以将菱形分成上下两个三角形,分析每行空格数和星号个数的关系) 代码如下: package com.homework.lhh; public class Ex20 { p ...

  4. 通过命令行提交更新代码到gitlab上

    解决方法: 1.打开命令行的窗口,定位到项目所在的路径. 2.输入:git status,敲回车查看代码是否有更新,有更新的话会出现文件改变的文件名.(红色的) 3.输入:git commit -a ...

  5. 引入CSS的方式、link和@import的区别

    引入CSS的方式有四种:内联方式.嵌入方式.链接方式.导入方式. 内联方式 内联方式指的是直接在 HTML 标签中的 style 属性中添加 CSS. <div style="back ...

  6. Docker 问题[Warning] IPv4 forwarding is disabled. Networking will not work.

    Docker 问题[Warning] IPv4 forwarding is disabled. Networking will not work. 在使用Dockerfile创建Docker镜像的时候 ...

  7. Centos7 安装编译nginx-1.9.6过程

    一.安装环境准备 使用编译安装nginx最好都先安装下这些依赖包 安装nginx需要的依赖库 yum install -y gcc patch libffi-devel python-devel zl ...

  8. Javascript调用本地数据库

    window.location.href = urls; // 本窗口打开下载 window.open(urls, '_blank'); // 新开窗口下载 (1)new ActiveXObject( ...

  9. eclipse搜索类快捷键

    习惯的编辑器可以提高编程效率,熟悉的快捷键可以提高工作效率,本文更新eclipse中常用的搜索快捷键 打开资源快捷键:Ctrl+Shift+R 通过在搜索框中输入名字可以很方便的在项目或工作空间中找某 ...

  10. Linux centos7 sed工具介绍

    一.sed上 grep工具功能只能实现查找,不能把查找的内容替换. sed本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行查找.删除.替换字符或字符串.调换字符串位置.直接修改文件内容等 ...