今天主要讲一下eventloop在浏览器中与在node中运行的机制,首先,不得不来讲一下,下面几个名词的概念。javascript
Node.js是一个基于 ChromeV8引擎的JavaScript运行环境(runtime),Node不是一门语言,而是让js运,行在后端的运行时,而且不包括javascript全集,由于在服务端中不包含DOM和BOM,Node也提供了一些新的模块例如http,fs模块等。css
Node.js 使用了事件驱动、非阻塞式 I/O 的模型,使其轻量又高效而且Node.js 的包管理器 npm,是全球最大的开源库生态系统。java
高并发,是指在同一时间并发访问服务器node
I/O密集指的是文件操做、网络操做、数据库,相对的有CPU密集,CPU密集指的是逻辑处理运算、压缩、解压、加密、解密ajax
用户界面-包括地址栏、前进/后退按钮、书签菜单等数据库
浏览器引擎-在用户界面和呈现引擎之间传送指令(浏览器的主进程)npm
渲染引擎,也被称为浏览器内核(浏览器渲染进程)后端
一个插件对应一个进程(第三方插件进程)promise
GPU提升网页浏览的体验(GPU进程)浏览器
渲染引擎内部是多线程的,内部包含两个最为重要的线程ui线程和js线程。
这里要特别注意ui线程和js线程是互斥的,由于JS运行结果会影响到ui线程的结果。
ui更新会被保存在队列中等到js线程空闲时当即被执行。
javascript在最初设计时设计成了单线程,为何不是多线程呢?
若是多个线程同时操做DOM那岂不会很混乱?这里所谓的单线程指的是主线程是单线程的,因此在Node中主线程依旧是单线程的。
js只能是单线程的 不能两个线程同时操做一个dom
ui进程与js进程是互斥的,不能同时执行,执行js后空闲下来了,再去执行css
浏览器事件触发线程(用来控制事件循环,存放setTimeout、浏览器事件、ajax的回调函数)
定时触发器线程(setTimeout定时器所在线程)
异步HTTP请求线程(ajax请求线程)
以下图所示:
下列代码中,函数是放到栈中的,看看它的执行顺序
function fn1() {
let a = 1;
fn2();
function fn2() {
console.log(a);
let b = 2;
function fn3() {
debugger;
console.log(b);
}
fn3();
}
}
fn1();
复制代码
执行结果以下图所示:
常见的(macro-task)宏任务:setTimeout setImmediate(只兼容ie) MessageChannel
常见的(micro-task)微任务:promise.then (MutationObserver);
了解了以上几个名词的概念以后,下面重点来了,先看一下EventLoop在浏览器中的运行机制
Promise.resolve('1').then(data => { console.log('第一个promise') });
setTimeout(() => {
console.log('setTimeout1')
Promise.resolve('2').then(data => { console.log('第二个promise') });
});
setTimeout(() => {
console.log('setTimeout2');
});
复制代码
代码运行的结果为:
第一个promise
setTimeout1
第二个promise
setTimeout2
复制代码
1,setTimeout有一个4ms的最短期,也就是说无论你设定多少,反正最少都要间隔4ms才运行里面的回调,因此先执行了第一个promise异步回调,输出了第一个promise
2,setTimeout到运行时间了,输出了setTimeout1,
3,依次输出了第二个promise(Promise的任务会在当前事件循环末尾中执行)
4,最后,第二个setTimeout到时间了,输出了setTimeout2
复制代码
EventLoop在node中的运行机制
nextTick(微任务)是队列切换时执行的
setTimeout和setImmediate顺序是不固定,看node准备时间
setImmediate(() => {
console.log('setImmediate1')
setTimeout(() => {
console.log('setTimeout1')
}, 0);
})
setTimeout(()=>{
process.nextTick(()=>console.log('nextTick'))
console.log('setTimeout2')
setImmediate(()=>{
console.log('setImmediate2')
})
},0);
复制代码
第一种状况,若是先执行了setImmediate函数,那么它的执行顺序为:
setImmediate1
setTimeout2
setTimeout1
nextTick
setImmediate2
复制代码
1,根据上图所示,若是先执行了setImmediate回调,把setImmediate1输出了,
2,接下来,会执行setTimeout回调,输出setTimeout2,
3,接着输出setTimeout1,接着微任务nextTick,
4,最后,输出setImmediate2
复制代码
第二种状况,若是先执行了setTimeout函数,那么它的执行顺序为:
setTimeout2
nextTick
setImmediate1
setImmediate2
setTimeout1
复制代码
1,根据上图所示,若是先执行了setTimeout回调,把setTimeout2输出了,
2,接下来,会执行poll轮询,那就是输出了nextTick,
3,接下来执行check队列中setImmediate函数,把setImmediate1输出了,check队列里的内容得先执行完,才能切换下一个队列,因此输出了setImmediate2,
4,最后循环到了setTimeout回调,输出了setTimeout1
复制代码
关于eventloop在不一样环境中运行的机制,首先要对上述提到的,队列&栈、微任务&宏任务要有深刻的理解,但愿这篇内容对你们有所帮助,固然也但愿你们若是有什么问题,能够随时加关注,进行讨论!