浏览器在渲染页面时需要将 HTML 标记转化成 DOM 对象
成都创新互联公司是一家专注于成都做网站、成都网站制作与策划设计,穆棱网站建设哪家好?成都创新互联公司做网站,专注于网站建设十余年,网设计领域的专业建站公司;建站业务涵盖:穆棱等地区。穆棱做网站价格咨询:18980820575
CSS 则会被转化成 CSSOM 对象
DOM 和 CSSOM 是独立的树形结构,
当 DOM 树和 CSSOM 树都构建完成的时候,他们就会合并在一起构建 render tree,因为要在页面上渲染不仅需要这个页面的结构,也需要知道整个页面的样式,所以 render tree 是 DOM 树和 CSSOM 树的结合体,有了 render tree,浏览器才能知道把什么内容按照什么样式渲染在屏幕上。
浏览器从获取 HTML 到最终在屏幕上显示内容需要完成以下步骤:
经过以上整个流程我们才能看见屏幕上出现渲染的内容,优化关键渲染路径就是指最大限度缩短执行上述第 1 步至第 5 步耗费的总时间,让用户最快的看到首次渲染的内容。
另外,这是一个渐进的过程。为达到更好的用户体验,呈现引擎会力求尽快将内容显示在屏幕上。它不必等到整个 HTML 文档解析完毕之后,就会开始构建呈现树和设置布局。在不断接收和处理来自网络的其余内容的同时,呈现引擎会将部分内容解析并显示出来,因为 HTML 采用基于流的布局模型,这意味着大多数情况下只要一次遍历就能计算出几何信息。处于流中靠后位置元素通常不会影响靠前位置元素的几何特征,因此布局可以按从左至右、从上至下的顺序遍历文档。但是也有例外情况,比如 HTML 表格的计算就需要不止一次的遍历。
从上面的整个流程我们已经知道,浏览器的渲染需要 render tree, render tree 需要 CSSOM 树才行,所以样式表的加载是会阻塞页面的渲染的,如果有一个外部的样式表处于下载中,那么即使 HTML 已经下载完毕,也会等待外部样式表下载并解析完毕才会开始构建 render tree。
脚本就更麻烦了,先明确一点, JS 引擎和 UI 的渲染引擎是互斥的,所以当脚本在执行的时候浏览器要将控制权就给 JS 引擎,等到 JS 执行完毕再还给 UI 引擎,不论这个脚本是以何种形式加载的,在执行时均会阻塞 UI 的渲染。
接下来分别看不同形式加载的脚本对页面渲染的阻塞情况:
内联的脚本随着 HTML 一起下载,在开始执行时已经完成了 字节 → 字符 → 令牌 → 节点 → 对象模型 的整个过程,所以不存在下载的时间(其实也不能这么说,下载的时间算在了 HTML 的下载时间中),执行时是会阻塞关键渲染路径的。
外部脚本的整个加载过程及执行过程都是阻塞关键渲染路径的。
带 defer/async 的脚本会与 HTML 并行下载,下载的过程不会阻塞 DOM 的构建,但是执行是会的,不同的是 defer 是在 DomContentLoaded 之前执行,async 是加载完之后立刻执行。
defer/async 的脚本在下载期间不会阻塞页面解析不是一个技术原因而是一个选择,因为内联脚本/外部脚本是要等待他们执行,所以不得不等待他们下载。而页面并不需要等待 defer/async 的脚本,所以他们的下载与页面的解析是并行的。
var dynamicScript = document.creatElement('script')
dynamicScript.src = 'sample.js'
document.head.appendChild(dynamicScript)
dynamicScript.onload = function(){...}
动态生成的脚本的下载过程不会阻塞页面的解析,执行会阻塞解析,有点 async 的感觉。
脚本不仅能够访问 DOM 元素,还能访问 DOM 的样式,如果将要执行脚本时浏览器尚未完成 CSSOM 的下载及构建,浏览器将延迟脚本执行和 DOM 构建,直至其完成 CSSOM 的下载和构建。
所以,CSSOM 的构建会阻塞 HTML 的渲染,也会阻塞 JS 的执行,JS 的下载与执行(内联及外部样式表)也会阻塞 HTML 的渲染。
为尽快完成首次渲染,我们需要最大限度减小以下三种可变因素:
优化关键渲染路径的常规步骤如下:
上面已经分析过了,样式表会阻塞渲染,在加载完毕之前是不会显示的,为了让用户以最快的速度看到页面上的内容,可以将页面的某一部分的样式抽离出来,单独放在一个样式表中或者内联在页面中,这样的样式称为关键样式,这部分样式会优先它可以是页面的骨架屏或者是用户刚加载进页面时看到的首屏的内容。
...body goes here