浏览器界面渲染与阻塞

本文最后更新于:6 个月前

一个网页主要由:HTMLCSSJavaScript、其他静态资源组成,而网页元素的结构、位置主要与其中的HTMLCSS有关,其他文件会对前两者的加载产生影响。

HTML网页

我们考虑最简单的情况,一个网页仅仅由HTML文件构成,那么这个网页的渲染流程如下:

image-20210119144843543

  1. Parser

  2. Render

  3. flow

    渲染完成后,若因为DOMTree的结构发生改变,界面需要重新渲染的行为称为reflow

  4. paint

    渲染完成后,若因为元素的样式发生改变,界面需要重新渲染的行为称为repaint

步骤2完成后,也即HTML文档被完整加载并解析为DOM元素后,触发DOMContentLoaded事件。

引入CSS

image-20210119145608379

图中情况:CSS的位置位于HTML之前时。

  • HTML解析:这其中步骤1与步骤5是异步进行的,CSS加载并不影响HTML解析为DOM元素,也即不会阻碍DOMContentLoaded事件。

  • HTML渲染:RenderTree 不同于DOMTree,其中包含了元素样式的描述,这些样式都来自于CSS,所以在步骤2进行前,需要等待CSS加载完毕,因此HTML的渲染会因为CSS的引入而被阻塞。需要这样做的原因在于:若是令HTML先进行渲染,那么在CSS文件加载完成后,样式改变需要重新渲染,那么这无疑加重了网页的性能负担。CSS文件一般在Header中引入也是这个目的(使得CSS先被加载好,HTML解析完成后一次渲染完成)。

引入JavaScript

image-20210119150104479

图中情况:三者的顺序为CSS-> JS ->HTML 时。

JavaScript存在于HTML之前时,HTML的解析都会被阻塞。

CSS若位于JavaScript之前时,CSS会阻塞JavaScript的执行。

结论

三者引入的位置影响到网页的加载速度。原则上:

  1. CSS优先引入,为了使DOM的渲染一次完成,因此放在首部。
  2. JavaScript 尽量少影响DOM的构建,因此放在底部。
  3. 若特殊情况下,必须将JavaScript 放在首部,则需要考虑它与CSS的优先关系。既然将其放在首部,意味着它的急需在网页加载的一开始进行执行,若其不需要引用CSSOM的内容,则可以将其放在CSS之前,防止被CSS`阻塞。

其他

loadDOMContentLoaded

  • DOMContentLoaded:指的是DOM元素全部解析完成。
  • load:则指的是网页的全部资源加载完成。

可以在DOMContentLoaded体验二者区别。

image-20210119173906174

display : nonevisibility : hidden 的区别

  • display : noneDOM元素不存在,手动将一个正常现实的元素改为display : none,将导致reflow事件触发。
  • visibility : hiddenDOM元素存在只是不显示,手动将一个正常现实的元素改为visibility : hidden只是从样式上将元素隐藏,导致的是repaint事件的触发。

deferasync

  • 相同点:

    • 异步执行
    • 对内联脚本不起作用
    • 不能调用document.write 方法
  • 不同点:

    • async会在load事件之前执行
    • defer会在DOMContentLoaded之前执行

参考

load/domContentLoaded事件、异步/延迟Js 与DOM解析

css、js阻塞

原来 CSS 与 JS 是这样阻塞 DOM 解析和渲染的