<link>和<script>和dom解析渲染之间的关系,及资源标识符的作用
script标签的位置不当的话,会阻塞html的解析,进而影响首屏速度
关键词解释
解析,渲染,触发页面paint。下载,执行
- 解析:html文件的解析(从上到下)
- 渲染:页面的渲染(能看见东西)
- 触发页面paint:触发页面渲染
- 下载(download):资源下载(缓存到浏览器)
- 执行:资源执行(run),等同于解析
link标签 和 script标签 和 dom解析 之间的关系
以下结论不带资源标识符(比如link的preload,script的async等),就纯标签
测试例子部分可以参考 juejin.cn/post/684490…
<link> | 带src 的 <script> (外链) | inline内联的 <script> | |
---|---|---|---|
DOM的解析(生成dom树) | 不会阻塞 | 会阻塞(但会有预解析,只解析外链[让资源并行下载] ,不会修改dom树) 并且需要等到css执行完,生成cssom tree后,才执行(可以先下载), *危害:让dom树和cssom树不能并行解析,变成串行解析了 | 同左 |
生成渲染树并渲染 | 会阻塞(没有样式的页面几乎无法看,而且还要浪费重排和重绘的性能,所以索性,等到css规则树生成完毕,才渲染) | 会阻塞 | 同左 |
触发页面paint(立刻生成渲染树并渲染 ) | 不会 | 解析之前会触发(渲染此<script>标签之前的元素) - 也有前提条件:1. 不在<head>内,在body内。2. 此前的link标签需加载并执行完毕 | 不会触发paint(因为不用下载,只需执行,多数情况下时间比较短) |
script 下载 | 不会阻塞 | ||
script 执行(解析) | 会阻塞(src和inline都会阻塞) | ||
link 下载 | 不会阻塞(因为link标签都是外链) | 同左 | |
link 执行(解析) | 会阻塞(会阻塞script标签下面的link标签,因为是从上到下执行) | 同左 |
如果script标签带上资源提示符
提示符是: async 和 defer
例如:<script src="1.js" defer></script>
目的:让script标签不阻塞 dom的解析 (一样会阻塞渲染)
script | script async | script defer | |
---|---|---|---|
script的下载(是否阻塞dom解析(生成dom树)) | 会阻塞(但会有预解析,只解析外链[让资源并行下载] ,不会修改dom树) | 不阻塞,并行 | 不阻塞,并行 |
script的解析执行(是否阻塞dom解析(生成dom树)) | 会阻塞 | 会阻塞 | 不阻塞,等到其他元素解析完成(dom树生成)后执行, DOMContentLoaded之前 |
script标签是否可能会乱序解析 | 不会 | 有可能 | 不会 |
如果link标签带上资源提示符
例如:<link rel="preconnect" href="https://code.jquery.com" as="script">
-
preconnect ( 对比 dns-prefetch )
提前 DNS查询,TLS协商,tcp握手
- 对当前域名的资源无效(因为已经有缓存了
- 一般对cdn或其他域的资源 有效
场景:页脚有个cdn资源<script>,则可以在页眉可以放一个preconnect资源提示
<head> <meta charset="utf-8"> <title>preconnect example</title> <link rel="preconnect" href="https://code.jquery.com/jquery-3.6.0.min.js" as="script"> </head> <body> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> </body>
对比:dns-prefetch, dns-prefetch只有DNS查询,多了2次RTT(Round-trip delay 往返延迟)
<link rel="dns-prefetch" href="https://fonts.googleapis.com/">
-
preload(用法几乎同上)
作用:提前加载资源:提前 DNS查询,TLS协商,tcp握手,和资源下载
支持的格式多:image,style,script,font,audio,video 等
场景:希望把 资源 放页脚(不阻塞dom解析),然后又想让资源提前下载,就可以用 preload + as="[type]"
建议不要滥用:因为他的优先级会提很高,只在会影响白屏时间的重点资源上使用(预加载)(不要所有的资源都加preload,优先级没那么高的资源,就不要跟优先级高的抢了)
<head> <meta charset="utf-8"> <link rel="preload" href="style.css" as="style"> <link rel="preload" href="main.js" as="script"> <link rel="stylesheet" href="style.css"> </head> <body> <h1>bouncing balls</h1> <canvas></canvas> <script src="main.js"></script> </body> ----------------- <head> <meta charset="utf-8"> <title>Video preload example</title> <link rel="preload" href="sintel-short.mp4" as="video" type="video/mp4"> </head> <body> <video controls> <source src="sintel-short.mp4" type="video/mp4"> <source src="sintel-short.webm" type="video/webm"> <p>Your browser doesn't support HTML5 video. Here is a <a href="sintel-short.mp4">link to the video</a> instead.</p> </video> </body>
-
prefetch(用法几乎同上)
作用:提前下载未来某个资源 (当前页面资源加载完了后,才会去预取)
-
预取“将来”的资源(比如下一个页面,用户也有概率不到下一个页面),优先级比preload低(因为是下一个页面,preload是作用于当前页面)
- 可以预下载资源到浏览器缓存,等到真正执行的时候,就直接拿缓存
场景:下一个页面有个cdn资源<script>,则可以在当前页加 个link标签 prefetch资源提示符
<link rel="prefetch" href="https://code.jquery.com/jquery-3.6.0.min.js" as="script"></link>
注意:
-
在 Chrome 中,如果用户导航离开一个页面,而对其他页面的预取请求仍在进行中,这些请求将不会被终止。
-
此外,无论资源的可缓存性如何,
prefetch
请求在未指定的网络堆栈缓存中至少保存 5 分钟。
-
码字不易,点赞鼓励!