学习和总结文章同步发布于 https://github.com/xianshanna...,有兴趣可以关注一下,一起学习和进步。
Http 优化方式是前端性能优化的重要部分,也是前端必备的知识点之一。
减少静态资源文件大小
这个是最根本的途径,假设真的有个 10 几兆以上的静态资源文件,不减少大小的情况下,即使优化做到了极致,用户体验也好不了哪里去。
如果整个网页就 2KB 大小的资源文件,不优化都很快。
代码层优化
- 只打包用到的依赖包,目前 webpack tree shaking 功能已经自动处理了,还有尽量少使用第三方依赖包(当然看情况啦)。
- 代码分割(code splitting),不同页面加载自己用到的代码,不加载其他页面的代码(其实也属于懒加载)。
传输层优化
Http 传承启用压缩传输方式。
一般我们开启 gzip,基本都能压缩 6 倍左右(一般都是文件越大,字符串相似率越大,压缩率越大)。
首先经过服务器压缩后,然后 Http 响应头 Content-Encoding
设置为相应的压缩方式,浏览器会自动解压的。
Content-Encoding: gzip
当然还有其他的压缩方式,如 compress、deflate 等等,目前使用最广的还是 gzip。
适当合并或者分散请求
合并请求或者分散请求需要看实际情况的。
合并请求
http 1.1
(包括 http1.1)之前的版本,浏览器存在同域名并发限制,谷歌目前是同域名并发现在为6 个请求,其他的浏览器或多或少,但也差不了多少。
如果是使用的是 http1.1
web 服务,那么我们首次加载的资源要基本保证在 4 个以内,所以静态资源请求数过多就要看情况进行合并请求了。
分散请求
Http2.0
没有同域名并发的问题,我们可以适当分散请求。当然如果在 Http1.1
一个资源文件过大,然后并发并没有达到限制,也可以拆分资源文件达到分散请求的目的。
使用预加载
预加载某些情况下可以大大提升加载速度进而提示用户体验。
预加载需要了解 preload
和 prefetch
的知识。
预加载 DNS
dns 解析也是需要时间的,特别在移动端的时候更明显,我们可以预解析 dns 减少不通域名 dns 解析时间。
其实还有个 preconnect,preconnect
不仅完成 DNS 预解析,同时还将进行 TCP 握手和建立传输层协议,但是浏览器有兼容性,目前用不上。
预加载静态资源
使用 preload
通过 preload
一般是预加载当前页面要用到的图片、字体、js 脚本、css 文件等静态资源文件。
场景一
如果需要,你可以完全以脚本化的方式来执行这些预加载操作。例如,我们在这里创建一个HTMLLinkElement
实例,然后将他们附加到 DOM 上:
var preloadLink = document.createElement("link");
preloadLink.href = "myscript.js";
preloadLink.rel = "preload";
preloadLink.as = "script";
document.head.appendChild(preloadLink);
这意味着浏览器将预加载这个JavaScript文件,但并不实际执行它。
如果要对其加以执行,在需要的时候,你可以执行:
var preloadedScript = document.createElement("script");
preloadedScript.src = "myscript.js";
document.body.appendChild(preloadedScript);
当你需要预加载一个脚本,但需要推迟到需要的时候才令其执行时,这种方式会特别有用。
场景二
字体是要使用到的时候才会去加载字体的(如果字体是自定义的字体,会发起 Http 请求加载字体)。
由于这个特性,我们可以预加载字体,待使用到字体的时候,字体已经加载完毕,无需等待加载。
如下我们没有 preload 的时候,代码也是可以运行的,但是字体加载是需要等待页面 JS、CSS 资源加载完毕后,当前页面使用到字体才会去加载的:
我们加上:
就可以提交加载,节省大部分甚至全部的字体加载时间,一般都是全部的时间,因为 JS 资源文件比字体大多了(并行下载,最长的资源加载时间,决定了最大加载时间)。
使用 prefech
prefetch
一般是预加载非当前页面的资源,prefetch
是一个低优先级的资源提示,允许浏览器在后台(空闲时)获取将来可能用得到的资源,并且将他们存储在浏览器的缓存中。当前页面加载完毕,才会开始下载 d带有 prefetch 标记的资源,然后当用户进入另外一个页面,已经 prefetched 的资源可以立刻从缓存中加载。
不过 prefech 的应用场景比较少。
采用懒加载
图片懒加载
这种做法一般都是在用户滚动到响应位置(当然从用户体验式来说,需要提前一点加载),才会加载响应的图片,图片特别多的网上基本都会做这个优化(如视频网站)。
或者幻灯片查看图片的时候,用户即将查查下一张图片的时候再加载,而不是一次性加载全部的图片。
JS 懒加载
需要用到相关 JS 时,通过动态创建 标签进行 JS 文件懒加载,如 Webpack 的 code splitting。
合理使用 defer 和 async
带有 defer
或 async
属性的 script 资源都会并行下载,而且不会影响页面的解析,从而达到了节省脚本下载时间。
两种的不同的在于:
带有 defer
属性的资源会按照顺序在页面出现的属性,资源加载完后,会在 DOMContentLoaded
事件调用之前依次执行。
带有 async
属性的资源则是下载完立即执行,可能在 DOMContentLoaded
事件之前或者之后执行,多个带有 async
属性的资源无执行顺序,谁先加载完成,谁先执行。
那么为什么可以节省下载时间?我们来对比一下。
defer
资源加载类似于把 放在