细说JS系列(三)

82 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情

铃铛说点题外话

上一篇文章里面说了浏览器解析我们代码的全过程,包括代码会不会影响其他渲染过程,也留下了一个问题:JS会不会阻塞DOM树渲染,答案:是。

为什么JS会阻塞DOM树呢,我们接下来就来看看

铃铛说正文

  1. JS操作DOM慢。因为DOM是属于渲染引擎中的东西,JS是JS引擎中的东西,当我们使用JS操作DOM,这个操作涉及两个进程之间的通信,所以在性能上一定会有损耗。操作DOM的次数越多,也就等同于一直在进行进程之间的通信,并且操作DOM还会带来回流。

  2. JS会阻塞DOM树。当渲染进程开始解析HTML文档时,会先开启一个预解析线程,遇到JS和CSS文件,预解析会提前下载这些数据。如果代码里引用了外部的CSS文件,那么在执行JS之前,要先将CSS文件下载完成,并解析成CSSOM对象之后,才能执行JS脚本。在JS引擎解析JS之前,是不知道JS是否操纵了CSSOM的,所以渲染引擎在遇见JS的时候,不管有没有操纵CSSOM,都会先执行下载CSS,解析操作,在执行JS。最后再继续构建DOM树,构建布局树,绘制页面。

  3. CSS加载会造成阻塞。DOM树和CSSOM树是并行构建的,所以css加载并不会阻塞DOM的解析。然而,渲染树是依赖于DOM树和CSSOM树的,也就是说只有CSS资源加载完成才会开始渲染。因此,CSS加载会阻塞DOM的渲染。由于JS可以操控DOM和CSS样式,如果在修改这些样式的时候同时渲染页面,就会发生数据不一致的情况,为了避免这种结果,浏览器设置渲染线程和JS引擎是互斥关系,因此样式表会在后面的JS执行前先加载执行完毕,所以,CSS会阻塞后面的JS执行。

  4. JS阻塞页面渲染。由于JS是可以操控DOM的,如果在修改元素的同时渲染页面,会造成前后数据不一致,为了解决这个问题,浏览器设置渲染线程和JS引擎为互斥关系。也就是说JS引擎在执行时,渲染线程被保存到一个队列里面等待被执行,等到JS引擎执行完毕,才会开始渲染页面。如果JS执行的时间过长,那么就会造成页面渲染的不连续,导致页面渲染加载有阻塞的感觉。

跟铃铛说再见

这一篇我们真的是用大量篇幅把浏览器再解析和渲染过程中能遇见的阻塞情况都一一列举了出来,并且详细的解释了造成影响和阻塞的原因。

下一篇我们就回归到“主线程”上,看看浏览器是如何解析JS代码的。