事件循环
-
关于chrome浏览器主要的进程
浏览器进程(界面显示、用户交互、子进程管理等)
网络进程:f负责加在网络资源,网络进程内部会启动多个线程处理不同的任务
渲染进程:渲染进程启动后,会开启一个渲染主线程,主线程负责执行HTML、CSS、JS代码
重点:默认情况下浏览器会每一个标签开启一个新的渲染的进程,以保证不同的标签页之间不相互影响。但是这种默认将来可能会发生改变,未来google可能采用一个站点一个渲染进程的方式
-
渲染主线程主要做哪些工作呢?
解析HTML
解析CSS
计算样式
布局
处理图层
每秒把页面画60次
执行全局JS代码
执行计时器的回调函数
-
为什么渲染进程不使用多个线程来处理这些事情?
多线程会带来上下文切换内
多线程会出现锁竞争导致的死锁问题
多线程会带来的了代码的复杂度
-
单线程是如何进程任务调度的呢?
渲染主线程想到一个绝妙的主意来处理这个问题,就是排队。
将所有要执行的任务都放入消息队列中,主线程通过一个不会结束的for循环不停的去执行队列中的任务
-
渲染主线程是如何解决阻塞的问题?
当主线程遇到需要等待的任务,如果setTimeout、setInterver、网络请求、事件监听
主线程会把他们交给对应的线程去执行。
比如setTimeout会交给计时器线程,计时器线程会调用系统内部的计时器,一旦计时器时间到达,就会将setTimeout上绑定的函数封装成一个任务对象,交给任务队列,然后渲染主线去执行任务队列里面的任务
-
如何理解JS的异步?
JS是一门单线程的语言,这是因为它运行在浏览器的渲染主线中,而渲染主线程只有一个。而渲染主线承担诸多任务,渲染页面、执行js都在其中执行的
如果使用同步的方式,就可能造成主线程阻塞,从而导致消息队列中的其他任务无法执行。这样会导致主线程白白浪费时间,页面还无法及时更新
所以浏览器采用了异步的方式来避免:
具体做法就是当某些任务发生时,比如计时器、网络、事件监听主线程将任务交给其他的线程去处理,自身立即结束任务的执行,转而继续执行后续的代码。当其他线程完成时,将事先传递的回调函数封装一个任务对象,加入消息队列的末尾,等待主线程的调度。
在这种异步模式下,浏览器永不阻塞,从而保证了单线程的流畅运行
-
JS为何会阻碍渲染?
function delay(duration){}//一个定时的死循环函数 btn.onlick=function(){ h1.textContent='很好很棒'; delay(3000);//死循环3000毫秒 }
以上代码的执行过程。
事件监听线程会在监听到用户点击时加函数加入到队列中,主线程去执行任务队列,当执行到
h1.textContent='很好很棒时',会创建一个绘制任务,将任务加入到队列中,加入之后会继续执行delay函数,只要执行完成主线程的任务时,才回去任务队列中,获取任务。所以绘制任务会在3000毫秒之后,被执行到。
-
任务是否有优先级?
任务时没有优先级的,在消息队列里面都是FIFO。但是消息队列是有优先级的
在老版本的中的浏览器中,会将队列分为宏队列、微队列。但是随着浏览器的复杂度的提升,W3C不再使用宏队列的说法
-
目前chrome的视线中,至少包含但不限于的队列
延时队列:用于存放在计时器达到时后,推送进来的任务。优先级:中
交互队列:用户存放监听到用户操作之后,推送进来的任务的。优先级:高
微队列:用户存放需要最快执行的任务,比如,Promise。优先级:最高
重点:队列中存储的并不是setTimeout或者Promise。而是他们触发之后,要执行的函数
-
简述一下JS的事件循环
事件循环或者消息循环,是浏览器渲染主线程的工作方式。
在Chrome的源码中,通过一个不会结束的for循环,每次循环从消息队列中取出第一个任务执行。
其他的线程只需要在被触发时,将任务加入到队列中即可。
过去把消息队列分为微队列和宏队列,这种说法目前已经无法满足复杂的浏览器环境,取而代之的是更加灵活多变的方式。
-
JS的中计时器能做到精确计时吗?
计算机硬件中没有原子钟,无法做到精确计时
受事件循环的影响,计时器只要在主线程空闲时才会运行,也会造成偏差
浏览器器在实现计时器时,如果嵌套超过5层,5层包含5层以后的所有计时器都有4毫秒的偏差
嵌套(setTimeOut(setTimeOut(setTimeOut(setTimeout))))