面试又被问到了js事件循环机制,这不狠狠总结一波。事件循环机制是一个非常重要的概念,不仅仅是面试,在笔试以及平时开发过程所遇到的一些问题,都可以通过事件循环机制来理解问题的本质再来解决。在面试的时候,面对这样一道常规的面试题,就一定不能仅仅是将事件循环讲清楚就结束了,一定要进行相应的扩展,毕竟难得遇到一道会的题目,这不争取拿个满分hhh~~
讲到事件循环机制,那就不得不提到两个很重要的概念了:渲染主线程和消息队列。
渲染主线程:
渲染主线程是渲染进程启动后开启的一个线程,负责解析执行HTML、CSS、JS代码。在之前关于浏览器渲染原理的文章也提到了渲染主线程这个概念,但其实渲染主线程是很忙的,它不仅仅要完成HTML解析,它还要做很多的事情,比如每秒把页面画60次,执行事件监听的回调,计时器的回调等等。
消息队列:
那么在那么多任务都需要执行的情况下,渲染主线程该如何调度任务呢?这时候第二个概念就出现了,那就是消息队列。消息队列简单来说,就是一个存放任务的地方,当渲染主线程在进行工作时,这时候有新的任务生成,那么这个新任务不会立即执行,会被加入消息队列中,等待渲染主线程的调度。当然,既然都叫队列了,那里面的任务当然也是先进先出,可以理解成排队。
总结:
既然清楚了两个概念,那就来完整的说一下事件循环的整体过程吧。
首先,渲染主线程的工作可以理解成是一个无限循环的过程(本质上就是无限for循环),每一次循环都会从消息队列中取出第一个任务进行执行,如果消息队列没有任务,那么渲染主线程就进入休眠状态,直到新的任务被添加,此时渲染主线程会被唤醒继续循环拿去任务工作。在这个过程中,其他所有线程可以随时向消息队列添加任务,新添加的任务会加在队列的末尾,等待渲染主线程的拿取执行。这整个过程就叫事件循环,也可以叫消息循环。
如下图:
OK,现在讲清楚了事件循环机制的过程,但还没完,在面试的时候,如果仅仅讲到这里就停止,那是远远不够的,还有一些值得探讨的问题。
渲染主线程在执行的过程中,会遇到一些问题,比如执行js代码时会遇到一些无法立即处理的任务,比如发送网络请求,或者设置定时器任务,或者事件监听(点击、滚动事件等等)任务,那渲染主线程怎么办?难道说要等计时完成后再继续工作吗?要知道,渲染主线程要每秒刷新页面60次,那岂不是定时器设置10秒那页面就要卡死十秒。显然是不可能的,这时候浏览器会通过异步的方式解决这种情况。
在面对刚刚提到的定时器等任务,渲染主线程不会等待,会将其交给其他线程,比如在处理计时器任务时,会将该任务交给计时线程,计时线程在计时完成后,不会立即将其回调函数交给渲染主线程去执行,而是会将回调函数封装成一个新的任务,加入到消息队列的末尾进行排队。这就是JS的异步执行机制。
了解了JS异步机制后,我们就清楚了,其实js中的定时器(setTimeout,setInterval)并不能够精确计时。
除了js异步机制以外,我们还可以聊聊任务和消息队列。
在操作系统中,我们知道,任务调度方式中有一种是优先调度(如果操作系统感觉准备的不太行的,就没必要提到这个,小心被拷打操作系统)。那在渲染主线程调度任务的过程中,任务有优先级吗?答案是:任务是没有的优先级的,在消息队列中就是先进先出。但是消息队列是有优先级的哦!
消息队列是有多种的,在以前一般就分为宏队列和微队列,微队列的优先级高于宏队列,所以渲染主线程会先从微队列中拿取任务,直到微队列空了之后再去宏队列中去拿取任务。
但随着浏览器的复杂程度越来越高,已经放弃这种划分方式了,微队列倒是不变,主要是把宏队列划分的更详细了。面试也不用提到太多,基本就提到以下三种队列就够了:
微队列:用户存放需要最快执行的任务,优先级最高
交互队列:用于存放用户操作后产生的回调任务,如点击事件,优先级中
延时队列:用于存放计时器到达后的回调任务,优先级低
讲到这里其实也就差不多了,不过我个人还喜欢再深入讲一下这个微队列的实现方式(手写promise会用到,后续我也会出相关文章)
一般就以下几种:
-
promise.then
-
nodejs中的process.nextTick
-
mutionobserver
既然讲到这个mutionobserver,你还可以跟面试官聊聊这个玩意。
mutionobserver是HTML5新增的Web API 接口,用于监视 DOM特定节点的增删改查。通过这个功能我们可以实现一些特别的功能,比如水印和广告的防去除功能,网页上一些没特殊处理的水印或者广告,我们可以通过脚本或者直接在浏览器调试工具中直接将对应元素删除即可。那这时候我们就可以通过mutionobserver监听水印元素是否被删除,如果被删除就立即重新添加回去即可(只能说这种方法也能被破除,防君子,不防小人hhh)。除此之外,还可以实现输入框的自动保存功能,mutionobserver能够监听指定dom元素的文本节点的改动,所以实现起来真的很方便。
至于具体的api使用,可以参考下面这篇文章
一文读懂 MutationObserver 的基本原理和应用场景
今天的文章就到这里啦,希望大家能有所收获~~
标签:面试题,优先级,渲染,队列,主线,搞定,JS,任务,循环 From: https://blog.csdn.net/zhtgg/article/details/140407653