当我们优化web 应用时,项目加载速度很慢,引用了很多大图片,和外部的js 和 图片等。在尝试切片,按需引入,懒加载等等手段之后可以试下link 的rel 属性它们带来的好处包括允许前端开发人员来控制资源的加载,减少往返路径并且在浏览页面时可以更快的加载到资源等等。
preload
指定页面很快就需要的资源,这些资源是你希望在页面生命周期的早期就开始加载的,早于浏览器的主要渲染机制启动。这可以确保它们更早可用,并且不太可能阻塞页面的渲染,从而提高性能。尽管名称中包含“load”一词,但它并不加载和执行脚本,而只是安排脚本以更高的优先级进行下载和缓存。
可以提高资源优先级, 预加载资源和缓存, 在用到的时候从缓存取
preload
还有其他优点。使用 as
来指定要预加载的内容类型允许浏览器:
示例代码 jquery 正常加载, main.js 采用preload , preload 提升资源加载顺序, 适用于 提前加载当前页面比较重要的资源
<head>
<meta charset="utf-8">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.js"></script>
<link rel="preload" as="script" href="https://mdn.github.io/html-examples/link-rel-preload/js-and-css/main.js">
</head>
image.png
prefetch
<link rel="prefetch"> 在浏览器中支持已久,但它是用于预取将在下一次导航/页面加载时使用的资源(例如,当你跳转到下一页时)。这是可以的,但对于当前页面没有用!此外,浏览器会给预取(prefetch)的资源比预加载(preload)的资源更低的优先级——当前页面比下一页更重要
通过图片可以看出,prefetch 不会提升资源的优先级 是在浏览器空闲的时候加载, 不需要指定 as 属性等, 适用于加载下一个页面资源,类似与requestIdleCallback ?
prefetch 的资源在网络堆栈中至少缓存 5 分钟,无论它是不是可以缓存的。
<!DOCTYPE html>
<html lang="">
<head>
<link rel="prefetch" href="https://mdn.github.io/html-examples/link-rel-preload/js-and-css/main.js">
</head>
<body>
<div id="app"></div>
<script defer src="https://mdn.github.io/html-examples/link-rel-preload/js-and-css/main.js"></script>
<!-- built files will be auto injected -->
</body>
</html>
image.png
dns-prefetch
DNS prefetching通过指定具体的URL来告知客户端未来会用到相关的资源,这样浏览器可以尽早的解析DNS。
当浏览器从(第三方)服务器请求资源时,必须先将该跨源域名解析为 IP 地址,然后浏览器才能发出请求。此过程称为 DNS 解析。虽然 DNS 缓存可以帮助减少此延迟,但 DNS 解析可能会给请求增加明显的延迟。对于打开了与许多第三方的连接的网站,此延迟可能会大大降低加载性能。
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="dns-prefetch" href="https://fonts.googleapis.com/" />
<!-- 其他 head 元素 -->
</head>
<body>
<!-- 你的页面内容 -->
</body>
</html>
preconnect
dns-prefetch
只执行 DNS 查询,而 preconnect
则是建立与服务器的连接。这个过程包括 DNS 解析,以及建立 TCP 连接,如果是 HTTPS 网站,就进一步执行 TLS 握手。将这两者结合起来,可以进一步减少跨源请求的感知延迟。你可以像这样安全地将它们结合起来使用:
<link rel="preconnect" href="https://fonts.googleapis.com/" crossorigin />
<link rel="dns-prefetch" href="https://fonts.googleapis.com/" />
prerender
-
<link rel="prerender">
在后台渲染指定的网页,如果用户导航到该页面,可以加速其加载。由于有可能浪费用户的带宽,Chrome 将prerender
视为 NoState 预取。
脚本和预加载
当你想要预加载一个脚本,但需要将执行推迟到确切需要它的时候,这很有用
// 动态预加载
function loadScript(url,type='preload',as="script"){
var link = document.createElement("link");
link.href = url
link.rel = type;
link.as = as;
document.head.appendChild(link);
}
// 执行
function execScript(url){
var script = document.createElement("script");
script.src = url;
document.body.appendChild(script);
}
// 加载这个js,但不执行
loadScript("myscript.js")
// 某个时机执行
setTimeout(function(){
execScript("myscript.js")
},1000)
Preload 和 Prefetch 的具体实践
Webpack插件之preload-webpack-plugin
大部分项目中都是通过打包工具将资源引入到html 中的, 而且将资源路径硬编码在了页面中(实际上,ticket_bg.a5bb7c33.png后缀中的hash是构建过程自动生成的,所以硬编码的方式很多场景下本身就行不通)。webpack插件preload-webpack-plugin可以帮助我们将该过程自动化,结合htmlWebpackPlugin在构建过程中插入link标签。
plugins: [
new HtmlWebpackPlugin(),
new PreloadWebpackPlugin({
rel: 'preload',
as(entry) {
if (/.css$/.test(entry)) return 'style';
if (/.woff$/.test(entry)) return 'font';
if (/.png$/.test(entry)) return 'image';
return 'script';
}
})
]
参考资料:
使用 Preload&Prefetch 优化前端页面的资源加载
preload
prefetch
requestIdleCallback
网友评论