浏览器资源的加载与解析的影响与原因

很多人对CSS、JS、媒体等资源文件的加载和解析会不会阻塞HTML的解析这类问题很模糊,即使稍微知道些,也不清楚其所以然,为了让大家理解的更深入一些,我便做了深入的研究的分析,本文就以问答的方式来解析这类问题的原由;

本文解决了以下问题,同时也是本文的目录

目录

内容

一 浏览器的渲染流程

在解释CSS和JavaScript资源的加载与解析都会阻塞什么之前,需要先简单介绍下浏览器的渲染机制,如下图:


渲染流程图

渲染流程有四个主要步骤:

  1. 解析HTML生成DOM树 : 渲染引擎首先解析HTML文档,生成DOM树
  2. 构建Render树 : 接下来不管是内联式,外联式还是嵌入式引入的CSS样式会被解析生成CSSOM树,根据DOM树与CSSOM树生成另外一棵用于渲染的树-渲染树(Render tree),
  3. 布局Render树 : 然后对渲染树的每个节点进行布局处理,确定其在屏幕上的显示位置
  4. 绘制Render树 : 最后遍历渲染树并用UI后端层将每一个节点绘制出来

以上步骤是一个渐进的过程,为了提高用户体验,渲染引擎试图尽可能快的把结果显示给最终用户。它不会等到所有HTML都被解析完才创建并布局渲染树。它会在从网络层获取文档内容的同时把已经接收到的局部内容先展示出来。

二 CSS

1 CSS的加载和解析会阻塞HTML的解析吗?

: CSS的加载和解析不会阻塞HTML的解析(即:不会阻塞Dom树的生成)

原因:
从上面的浏览器渲染流程中可以得出,HTML 解析成 Dom 树的过程 和 样式表解析成 CSSOM 树的过程是并行的,所以 CSS 的解析不会阻塞 HTML 的解析! 既然这样,那么 CSS 的加载 与 HTML 的解析 之间更没有依赖关系了,所以, CSS 的加载也不会阻塞 HTML 的解析;

2 CSS的加载和解析会阻塞什么?

: CSS的加载和解析不会阻塞HTML的解析,但会阻塞 渲染树 RenderTree 的生成,也会阻塞界面的渲染!

原因:
从上面的浏览器渲染流程中可以得出,渲染树 RenderTree 是根据 Dom 和 CSSOM 生成的,所以,在 CSSOM 还未完成之前, 是无法生成渲染树的,之后的流程更是无法进行;所以 CSS的加载和解析会阻塞 生成渲染树 RenderTre及其之后的流程;

3 对于不符合media设置的link还会加载其对应的CSS文件吗?

: 即使 link 标签的 media 属性的值不符合当前设备,浏览器也仍会加载其对应的CSS文件!
原因:
虽然当前设备中浏览器的状态不符合 media 属性的要求,但是接下来可能会符合 media 属性的要求,从而会用到其对应的 CSS 文件,比如:用户在浏览器上执行了 打印 操作,或者,用户改变了浏览器的尺寸,以使得浏览器匹配 media 属性的要求,等等;所以,即使 link 标签的 media 属性的值不符合当前设备,浏览器也仍会加载其对应的CSS文件,以便在接下来任何需要的时候使用!

三 JavaScript

1 JS的执行会阻塞HTML的解析吗?

: 所有的JS的执行,都会阻塞 HTML 的解析;即使设置了 defer 或 async 也是一样,只是设置了 defer 之后,js 会等到 HTML 解析完成之后再执行;

注意:
async 与 defer 属性对于 inline-script 都是无效的,所以下面这个示例中三个 script 标签的代码会从上到下依次执行:

<script async>console.log("1")</script>
<script async>console.log("2")</script>
<script async>console.log("3")</script>

原因:
假如有如下代码:

代码示例1:

<body>
    <div id="div1">元素1</div>
    <script>
        var newEle = document.createElement("div");
        newEle.id = "newEle";
        newEle.innerText = "新元素";
        document.body.appendChild(newEle);
    </script>
    <div id="div2">元素2</div>
    <div id="div3">元素3</div>
    
</body>

代码中,JS往Dom树的末尾追加一个新元素;我们的预期效果是这样的:

代码示例1预期效果

即:新元素 是显示在 元素1 下,被加在 script 元素下;

但是:如果在执行 JS 时不阻塞 HTML 的解析,那么当 JS 执行到 往 Dom 树中追加元素这条语句 document.body.appendChild(newEle); 时,HTML 可能已经解析到 元素3 了,则这时再追加 新元素 就会把 新元素 添加到 元素3 下,如下图所示:

代码示例1-问题效果

所以,为了避免类似的问题发生,在执行 js 时,是要阻塞 HTML 的解析的;

2 JS的加载会阻塞HTML的解析吗?

: 没有设置 defer 或 async 的 js的加载会阻塞HTML的解析(即:会阻塞Dom树的生成),设置了 defer 或 async 的 js 不阻塞 HTML 的解析;

原因:
这个问题的原因和上面的 JS的执行会阻塞HTML的解析 的原因是一样的;
参考 代码示例1:在加载 没有设置 defer 或 async 的 js时,如果不阻塞 HTML 的解析的话,那么当 JS 加载完成时, HTML 可能已经解析到 元素3 了,则这时再追加 新元素 就会把 新元素 添加到 元素3

所以,为了避免类似的问题发生,在加载没有设置 defer 或 async 的 js时,是会阻塞HTML的解析的;

3 浏览器会并行加载多个没有设置defer或async的js资源吗?

: 不会;浏览器同时只会加载1个没有设置 defer 或 async 的 js资源!

原因:
如果浏览器要并行加载多个 js 资源,则意味着浏览器在加载 js 资源时,不能阻塞 HTML 的解析,因为浏览器若要并行加载下面的 js 资源,那么浏览器就得继续解析下面的 HTML 标签,当解析到下面的 script 时,就会继续加载该标签对应的资源; 然而,上文已经讨论了,没有设置 defer 或 async 的 js的加载是会阻塞HTML的解析的,所以:浏览器同时只会加载1个没有设置 defer 或 async 的 js资源!

4 script标签的defer和async属性的区别

defer 与 async 属性对于 inline-script 都是无效的,所以下面这个示例中三个 script 标签的代码会从上到下依次执行;

<script async>console.log("1")</script>
<script async>console.log("2")</script>
<script async>console.log("3")</script>

对于设置了 src 属性的 script 标签,defer 与 async 会改变了 script 对HTML解析阻塞的情况,这两个属性都会使 script 异步加载,然而执行的时机是不一样的,详情见下图:

script的阻塞示意图
  • 蓝色线代表 script 脚本文件的网络读取过程;
  • 红色线代表 script 脚本的执行过程;
  • 绿色线代表 HTML 的解析过程;

5 js能获取到::before::after对应的元素吗?

: js不能获取到::before::after对应的元素!

原因:
JS 能获取到的是 Dom 树上的元素,即存在于 HTML 中的元素,而 ::before::after 这样的元素并不存在于 Dom 树上,而是存在于 渲染树 RenderTree 上;渲染树是根据 Dom树 和 CSSOM 生成的,::before::after 元素 之所以存在 渲染树上,是因为 CSS 给::before::after 元素 设置了样式,所以,CSS 选择器能够选中 ::before::after 对应的元素,但 JS 不能获取其对应的 Dom 元素;

四 媒体资源

1 媒体资源(如:图片音视频等)的加载会阻塞HTML的解析吗?

: 媒体资源的加载不会阻塞HTML的解析!
原因:
HTML的解析不依赖于这此媒体资源,这些媒体资源也不会影响当前Dom树的结构,所以,这些媒体资源的加载不会且也没有必要阻塞HTML的解析!

2 媒体资源是并行加载的吗?

: 媒体资源是并行加载的!
原因:
因为媒体资源的加载不会阻塞HTML的解析,那么,浏览器加载第一个媒体资源时,HTML还可以继续往下解析,当解析到其它媒体资源的标签时,浏览器还可以继续加载相应的媒体资源,所以媒体资源是并行加载的!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容