三个关键字:
EventLoop: 事件循环
MicroTask: 微任务
MacroTask: 宏任务
三个要点:
- js是单线程语言
- 任务队列
- EventLoop 是js的执行机制
一 js为什么是单线程语言?
js是单线程语言与它的用途相关,js是浏览器脚本语言,主要用于与用户的交互以及操作dom节点,所以要避免复杂的同步问题,这就决定了它必须是单线程的。比如:假如js是多线程的,一个线程在dom节点上添加内容,一个线程删除该dom节点,这时浏览器该怎么执行?
二 任务队列
2.1 同步任务和异步任务
由于js是单线程的,所以就意味着任务需要排队执行,任务又分为同步任务和异步任务。
同步任务:在主线程上排队执行的任务,只有前一个任务执行完才会执行下一个任务,如果前一个任务耗时长,后一个任务就会一直等待,容易造成阻塞。
异步任务:最开始不进入主线程,而是进入任务队列中的任务,当主线程执行完毕,系统会去查看任务队列,然后决定执行哪个异步任务,异步任务的执行顺序就和EventLoop机制,即微任务和宏任务相关。
异步执行的运行机制:
- 首先执行主线程上的代码,形成执行栈,遇到异步任务就将它放入任务队列中。
- 主线程执行完毕,系统会查看任务队列,某个任务可以执行时,就进入执行栈中开始执行。(如果有微任务就执行所有的微任务,没有微任务就执行下一个宏任务, 每个宏任务执行完都要清空所有的微任务)。
2.2 异步任务之微任务与宏任务
js是单线程的,所有的异步任务都被放入到任务队列当中,任务队列又分为两类:微任务和宏任务。
微任务:
process.nextTick(先于promise执行)
promise
Object.observe
MutaionObserver
宏任务:
setTimeout
setInterval
setImmediate
IO
UI rerendering
三 Event Loop
主线程从任务队列中读取任务的过程是循环的,所以整个的运行机制被称为 Event Loop(事件循环)。
例子:
console.log('main1');
process.nextTick(function() {
console.log('process.nextTick1');
});
setTimeout(function() {
console.log('setTimeout');
process.nextTick(function() {
console.log('process.nextTick2');
});
}, 0);
new Promise(function(resolve, reject) {
console.log('promise');
resolve();
}).then(function() {
console.log('promise then');
});
console.log('main2');
结果:
- 开始执行代码输出main1, process.nextTick放到执行栈末尾,setTimeout 放到宏任务,new promise 立即执行输出promise,then方法放到微任务,执行最后一句代码输出main2。
- 主线程执行完毕,开始清空微任务,执行process.nextTick输出process.nextTick1, 在执行then输出promise then。
- 执行下次event loop,执行setTimeout输出 setTimeout,里面的 process.nextTick放到当前执行栈末尾,当前宏任务执行完毕,执行微任务,输出process.nextTick2。
四 node中的Event Loop
Node的执行过程
- v8引擎解析js脚本
- 调用node API
- libuv库执行node api, 将不同的任务分给不同的线程执行,以异步的形式将结果返回给v8引擎
- v8引擎将结果返回给用户
Node的EventLoop的过程
Node的EventLoop由6个任务阶段组成,每个阶段都有自己的任务队列,每当进入某个阶段,都会从所属的队列中取出任务来执行,当队列为空或者被执行任务的数量达到系统的最大数量时,进入下一阶段。这六个阶段都执行完毕称为一轮循环。
六个阶段具体而言:
- timers:执行setTimeout() 和 setInterval()中到期的callback。
- I/O callbacks:上一轮循环中有少数的I/Ocallback会被延迟到这一轮的这一阶段执行
- idle, prepare:仅内部使用,process.nextTick就属于这一类
- poll:最为重要的阶段,执行I/O callback,在适当的条件下会阻塞在这个阶段
- check:执行setImmediate()的callback
-
close callbacks:执行close事件的callback,例如socket.on("close",func)
参考文章:
https://www.cnblogs.com/wuguanglin/p/EventLoop.html(Node的EventLoop机制讲的比较好)