上述打开一个页面的过程有很多优化点,包括前端和客户端,常规的前端和后端的性能优化在 PC 时代已经有最佳实践,主要的是:
1.降低请求量:合并资源,减少 HTTP 请求数,minify / gzip 压缩,webP,lazyLoad。
2.加快请求速度:预解析DNS,减少域名数,并行加载,CDN 分发。
3.缓存:HTTP 协议缓存请求,离线缓存 manifest,离线数据缓存localStorage。
4.渲染:JS/CSS优化,加载顺序,服务端渲染,pipeline。
其中对首屏启动速度影响最大的就是网络请求,所以优化的重点就是缓存,这里着重说一下前端对请求的缓存策略。我们再细分一下,分成 HTML 的缓存,JS/CSS/image 资源的缓存,以及 json 数据的缓存。
HTML 和 JS/CSS/image 资源都属于静态文件,HTTP 本身提供了缓存协议,浏览器实现了这些协议,可以做到静态文件的缓存。
总的来说,就是两种缓存:
1.询问是否有更新:根据 If-Modified-Since / ETag 等协议向后端请求询问是否有更新,没有更新返回304,浏览器使用本地缓存。
2.直接使用本地缓存:根据协议里的 Cache-Control / Expires 字段去确定多长时间内可以不去发请求询问更新,直接使用本地缓存。
前端能做的最大限度的缓存策略是:HTML 文件每次都向服务器询问是否有更新,JS/CSS/Image资源文件则不请求更新,直接使用本地缓存。那 JS/CSS 资源文件如何更新?常见做法是在在构建过程中给每个资源文件一个版本号或hash值,若资源文件有更新,版本号和 hash 值变化,这个资源请求的 URL 就变化了,同时对应的 HTML 页面更新,变成请求新的资源URL,资源也就更新了。
json 数据的缓存可以用 localStorage 缓存请求下来的数据,可以在首次显示时先用本地数据,再请求更新,这都由前端 JS 控制。
这些缓存策略可以实现 JS/CSS 等资源文件以及用户数据的缓存的全缓存,可以做到每次都直接使用本地缓存数据,不用等待网络请求。但 HTML 文件的缓存做不到,对于 HTML 文件,如果把 Expires / max-age 时间设长了,长时间只使用本地缓存,那更新就不及时,如果设短了,每次打开页面都要发网络请求询问是否有更新,再确定是否使用本地资源,一般前端在这里的策略是每次都请求,这在弱网情况下用户感受到的白屏时间仍然会很长。所以 HTML 文件的“缓存”和跟“更新”间存在矛盾。