前端知识笔记 - 性能
本文章总结 https://github.com/thedaviddias/Front-End-Checklist
内部,非原创性内容。
最佳实践
全局目标
- 第一幅有意义的绘图在 1s 内
- 对于平均配置交互时间应该小于 5s (平均配置批 200$ 内的安卓设备在慢 3G 网络 400ms RTT 和 400kpbs 的传输速度)
- 严格限制文件大小在 170kb 以内(gzip 后), 可以使用
npx size-limit --why
查看占用情况(https://evilmartians.com/chronicles/size-limit-make-the-web-lighter),相当于 vue 提供的 report 选项。
其他
- HTML 进行压缩
- 使用懒加载,包括图片,script,css 等。参见各自的优化方式
- cookie 大小限制。cookie 大小每个不要超过 4096 byte,域名下不要超过 20 个 cookie
- 第三方组件:第三方的 iframe 或者组件如果依赖外部 js 可以使用静态组件替代,减少调用
为即将到来的请求优化
DNS 解析(dns-prefetch)
即将进行解析的域名进行获取
<link rel="dns-prefetch" href="https://example.com">
预连接(preconnect)
对于即将请求的服务提前进行 DNS 查找, TCP 握手和 TLS 协商
<link rel="preconnect" href="https://example.com">
预获取(prefetching)
<link rel="prefetch" href="image.png">
预加载(preloading)
要在 body 中加载的进行提前加载
<link rel="preload" href="app.js">
preload 和 prefetch 的使用区别
本部分提取 https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf 的主要内容
prefetch 和 preload 区别: preloading 是声明未获取,会强制浏览器发起请求进行加载,不会阻塞文档的 onload 事件。 prefetch 则是告诉浏览器该资源可能用到,由浏览器决定何时获取。
preload 可提升 10% 交互时间,
什么时候使用 preload 和 prefetch
preload 资源仅限于该资源加载的可能性非常高时,prefetch 用于将来可能被使用时。
浏览器缓存策略
chrome 有四种策略: HTTP 缓存,内存缓存,service Worker 缓存,和Push 缓存。两种资源最终均使用 HTTP 缓存
是否最终缓存取决于缓存策略。
chrome 对于 preload 和 prefetch 的加载优先级
preload 使用 as 会和对应的类型加载优先级相同,否则会优先于 XHR。具体优先级可在 devtools 中添加priority 列。
图片(在当前视图中的)在加载过程中是有相对比较高的优先级,所以最好对图片实行懒加载。
使用预加载是否会浪费带宽?
使用 preload 或 prefetch ,可能会导致浪费带宽,尤其是没有设置资源缓存的时候。
chrome 在使用 preload 加载脚本,但3秒内没有使用它时会有警告。
出现两次获取资源的原因
- 不要使用 prefetch 作为 preload 的 fallback。
- 不要 preload 同时使用 fetch()。这个是 bug, xhr 没有该问题,会命令缓存
- 提供 as 参数,否则可能会下载两次。
- preload 字体不使用 crossorigin 会导致两次获取。
- 有 integrity 属性的资源无法利用 preload 的资源,会两次获取(注: integrity 是资源的一个摘要,防止资源被恶意篡改)
最后要注意: 不要给所有资源添加 preload,只为最近要加载的资源设置。
是否应该为我所有的资源添加 preload ? 有没有限制只 preload 最多 6 条的原则?
这个取决于你服务器有多少资源要加载和你用户的带宽以及其他的一网络状况。
很可能用到的请使用 preload,其他重要的使用 prefetch。对于 script 来讲,preLoad 关键的 bundle 比使用 <script async></script>
要好的多,同时你可以 preload 图片、样式,字体、媒体等。需要自己明确你页面中最先用到哪个资源。
prefetch 有特殊的属性要注意
chrome 中,如果用户从一个页面中 prefetch 了一个资源,跳转到新页面时还会在 flight 状态,请求不会结束。另外, prefetch 的资源不管是否设置了缓存,都会在 net-stack 中缓存至少 5 分钟。
使用 js 实现的 preload 和 rel=preload
或者 preload 的header 有什么区别?
preload 是和 js 处理执行是解耦的,preload 标记会被 chrome 扫描,也就不管 preload 标签在 HTML 什么问题,都会被提前捕获。这种实现比 js 实现更为强大
是否应该使用 http2 的 push 功能来替代 preload?
使用 push 的情况在于你知道确切的资源加载顺序,有 service worker 来拦截能够被缓存的请求。preload 能够将开始下载的时间提前到最开始的 request,不管是否为第三方资源。
这种要根据特性来, preload 在于和执行解耦,且有缓存策略,它的执行不会阻止执行其他内容。
push 不能使用第三方,直接下发资源对于浏览器来讲回路更短,但它只在你明确知道你在做什么的时候才能提高性能。
什么是链接的 preload 头?和 preload 的标签有什么区别?和 HTTP2 的 push 有什么关系?
请求头的方式:
Link: <https://example.com/other/styles.css>; rel=preload; as=style
区别在于:使用 headers 时可能会触发 HTTP2。使用 tag 不会触发 push.
如何对 rel=preload 链接进行浏览器是否支持检测?
const preloadSupported = () => {
const link = document.createElement('link');
const relList = link.relList;
if (!relList || !relList.supports)
return false;
return relList.supports('preload');
};
能否对已经加载的 preload css 样式进行设置为 stylesheet?
preLoad 是基于异步的载入,可以在 onload 时设置
<link rel="preload" href="style.css" onload="this.rel=stylesheet">
其他 preload 应用
用于加载 web 字体,异步加载 css,当前页的 js 脚本加载
支持 preload 和 prefetch 的浏览器
preload 支持 50%, prefetch 70%, 可参考 can i use
各类型的性能最佳实践
其他基础性能提高
HTML
清理注释,压缩 HTML
CSS
- Concatenation: 所有 CSS 样式合在一起
- Minification: 压缩 css
- Non-blocking: 不阻塞 DOM 进行加载样式,可以考虑使用 loadCSS 进行加载
- Unused CSS:移除不使用的 CSS 代码,使用 devTool 中的 coverage 来查看, 与代码集成 PurgeCSS 或 purifyCSS
图片
- 优化,使用 webp 等格式
- 使用 Sprite 图
- 懒加载
js
- js 文件合并
- 最小化压缩
- 不阻止渲染加载
- 优化和更新 js 库