目录
一、什么是事件循环机制?
概念:Event Loop就是
事件循环,是指浏览器或Node
的一种解决javaScript
单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。
1.JS的执行过程?
看下下面这段代码的执行顺序
正确的执行顺序应该是序号111,333,222
console.log('111'); //第一个被打印出
setTimeout(() => {
console.log('222')
}) //第三个被打印出
console.log('333') //第二个被打印出
EventLoop 事件循环机制的实现流程?
实现原因是JS引擎指向代码是自上而下执行的,并且先实行同步代码在执行异步代码。
所以首先会执行序号111这个语句,JS引擎会将这个语句放在调用栈当中,然后执行代码,将序号111打印在控制台当中,当这段代码执行完毕之后,便将这段代码从调用栈中移出去。
然后开始执行后续的代码,此时setTimeout这段代码进入调用栈,这段代码,会调用Web API,2秒之后进入callback队列,此时JS引擎将setTimeout移出调用栈,继续执行后面的代码,所以屏幕上会先打印出序号1,3,此时eventLoop登场了,它会不断循环的访问callbackqueue(回调队列),等2s之后Web API会将要执行的打印序号2这句话放入callbackqueue,eventLoop将callbackQueue中的内容放入调用栈,开始执行,然后屏幕上打印出序号2,这就是eventLoop的基本流程。
2.执行顺序图解
3.事件循环是什么
JS的运行机制就是事件循环
二、JS的执行顺序是什么?
- JS是从上到下一行一行执行。
- 如果某一行执行报错,则停止执行下面的代码。
- 先执行同步代码,再执行异步代码
三、事件循环的执行过程?
- 同步代码,调用栈执行后直接出栈
- 异步代码,放到Web API中,等待时机,等合适的时候放入回调队列(callbackQueue),等到调用栈空时eventLoop开始工作
- 微任务执行时机比宏任务要早
- 微任务在DOM渲染前触发,宏任务在DOM渲染后触发
console.log('111'); //第一个被打印
setTimeout(() => {
console.log('222') //第四个被打印
})
Promise.resolve().then(() => { //第三个被打印
console.log('444')
})
console.log('333') //第二个被打印
四、微任务和宏任务的根本区别
宏任务: setTimeout,setlnterval,Ajax,DOM事件,
- 宏任务是由浏览器规定的
微任务:Promise ,async/await
- 微任务是由ES6语法规定的
微任务执行时机比宏任务要早 (先记住)
五、事件循环的整体流程
- 先清空call stack(调用栈)中的同步代码
- 执行微任务队列中的微任务
- 尝试DOM渲染
- 触发Event Loop反复询问callbackQueue(回调队列)中是否有要执行的语句,有则放入call back继续执行
微任务的执行过程:
- 设置microtask(微任务)检查点标志为true。
- 当事件循环microtask执行不为空时:选择一个最先进入的microtask队列的microtask,将事件循环的microtask设置为已选择的microtask,运行microtask,将已经执行完成的microtask为null,移出microtask中的microtask。
- 清理IndexDB事务
- 设置进入microtask检查点的标志为false。
六、NodeJS的Event Loop
Node中的 Event Loop是基于libuv实现的,而libuv是 Node 的新跨平台抽象层,libuv使用异步,事件驱动的编程方式,核心是提供i/o的事件循环和异步回调。libuv的API包含有时间,非阻塞的网络,异步文件操作,子进程等等。 Event Loop就是在libuv中实现的。
Node
的Event loop
一共分为6个阶段:
- timers: 执行setTimeout和setInterval中到期的callback。
- pending callback: 上一轮循环中少数的callback会放在这一阶段执行。
- idle, prepare: 仅在内部使用。
- poll: 最重要的阶段,执行pending callback,在适当的情况下回阻塞在这个阶段。
- check: 执行setImmediate(setImmediate()是将事件插入到事件队列尾部,主线程和事件队列的函数执行完成之后立即执行setImmediate指定的回调函数)的callback。
- close callbacks: 执行close事件的callback,例如socket.on('close'[,fn])或者http.server.on('close, fn)。
Node 与浏览器的 Event Loop 差异:
浏览器环境下,microtask 的任务队列是每个 macrotask 执行完之后执行。而在 Node.js 中,microtask 会在事件循环的各个阶段之间执行,也就是一个阶段执行完毕,就会去执行 microtask 队列的任务。
总结:
浏览器和 Node 环境下,microtask 任务队列的执行时机不同
- Node 端,microtask 在事件循环的各个阶段之间执行
- 浏览器端,microtask 在事件循环的 macrotask 执行完之后执行