###前言
浏览器输入url到页面加载、渲染,这一过程经历了什么,这是我在面试中遇到过的问题。
但是我只回答了:
DNS域名解析
TCP连接
HTTP请求
服务器响应
客户端渲染
面试官就问我客户端是怎么渲染……嗯?
这个似乎是看过,但是忘记了,所以我就随便说了几句话,然后面试完后台就灰啦。这是很基础的问题,作为前端开发者,怎么能连浏览器渲染html的过程都不知道呢。
那么我们开始吧。
学习自文章:浏览器的渲染
客户端渲染HTML过程
处理 HTML 标记并构建 DOM 树。
处理 CSS 标记并构建 CSSOM 树。
将 DOM 与 CSSOM 合并成一个 Render 渲染树。
根据渲染树来布局,以计算每个节点的几何信息。
将各个节点绘制到屏幕上
CSS和Javascript阻塞资源
首先,我们要明确一个知识点,CSS和JavaScript会阻塞渲染。
CSS被视为阻塞渲染的资源,意味着浏览器将不会渲染任何已处理的内容,直到CSSOM构建完毕;
JavaScript不仅可以读取和修改DOM属性,还可以读取和修改CSSOM属性;
CSSOM构建时,JS执行将暂停,直到CSSOM就绪;
渲染树(Render-Tree)的关键渲染路径中,要求同时具有 DOM 和 CSSOM,之后才会构建渲染树。
即,HTML 和 CSS都是阻塞渲染的资源。HTML显然是必需的,因为包括我们希望显示的文本在内的内容,都在 DOM 中存放,那么可以从 CSS 上想办法。
用媒体类型和媒体查询来解除对渲染的阻塞。
复制代码
第一个资源会加载并阻塞。
第二个资源设置了媒体类型,会加载但不会阻塞,print声明只在打印网页时使用。
第三个资源提供了媒体查询,会在符合条件时阻塞渲染。
而JS比CSS更复杂点,例如:
Do not go gentle into that good night,
Old age should burn and rave at close of day;
Rage, rage against the dying of the light.
Do not go gentle into that good night,
Old age should burn and rave at close of day;
Rage, rage against the dying of the light.
复制代码
这样的 script 标签会阻塞 HTML 解析,无论是不是 inline-script。上面的 P 标签会从上到下解析,这个过程会被两段 JavaScript 分别打断一次(加载并且执行的时间段内)。
实际工程时,我们常将资源放到文档底部。
改变资源阻塞
defer/async
首先,注意 async 与 defer 属性对于inline-script 都是无效的,所以下面这个示例中三个 script 标签的代码会从上到下依次执行。
console.log("1");
console.log("2");
console.log("3");
复制代码
defer\async针对设置了 src 属性的 script 标签。
使用方法:
复制代码-
区别
defer
延迟执行引入的js文件,并行加载,等待document解析完毕,defer加载完毕,再按照顺序执行,接着触发DOMContentLoaded事件;
async
异步执行引入的js文件,加载好就开始执行,无论html解析阶段还是DOMContentLoaded触发之后。这种方式加载的 JavaScript 依然会阻塞 load 事件。换句话说,async-script 可能在 DOMContentLoaded 触发之前或之后执行,但一定在 load 触发之前执行。
document.createElement('script').async
document.createElement('script').async创建script默认是异步的。
动态添加script标签引入JavaScript文件默认不会阻塞页面,如果想同步执行,需要把async的属性人为设置为false。
使用document.createElement创建link元素,引入资源,在Chrome中不会阻塞。
const style = document.createElement("link");
style.rel = "stylesheet";
style.href = "index.css";
document.head.appendChild(style); // 阻塞?
复制代码
document.write,innerHTML
不推荐,不太可行。