需求背景
Vue, React 等框架简化了 SPA 开发,由于打包了整个应用,用户首次打开时需要加载全部代码,速度慢,严重影响用户体验,Bounce Rate 居高不下
用户通常只浏览网站少数页面,大部分的页面代码不需要全部加载进来,需要实现网站代码按需加载
随着网站不断完善,功能越来越多,第三方 npm 包占据大量代码空间,导致加载速度慢
解决方案
异步加载
浏览器的机制:解析过程遇到脚本标签,如<script src="a.js"></script>
会暂停内容解析,优先下载脚本,完成后继续解析。同步模式的阻塞问题可以通过 async 和 defer 属性实现异步加载,提高访问速度。
<script type="text/javascript" src="./a.js" async></script><script type="text/javascript" src="./b.js" defer></script>
Note: async、defer 属性是 HTML5 中的新属性,使用时需要注意区别,async加载后立即执行代码,需要注意js文件的依赖问题,避免冲突,无依赖可放心使用,典型例子google analytics
动态加载
由于异步加载的依赖问题难以控制,利用 webpack 实现动态加载成为 SPA 优化的主要方式。ES6 语法中提供import、export方式管理模块。其import关键字是被设置成静态的,不支持动态绑定。不过在es6的stage 3规范中,引入了一个新的方法 import() 使得动态加载模块成为可能。
Vue 中在 router.js 中添加 /* webpackChunkName: "test" */
注释分割代码,实现动态加载相应代码,达到按需加载的目的。
import Vue from 'vue';import Router from 'vue-router';Vue.use(Router);export default new Router({ mode: 'history', base: process.env.BASE_URL, routes: [ { path: '/test', name: 'test', component: () => import(/* webpackChunkName: "test" */ './views/Test.vue'), }, ]});
CDN
无论是否为 SPA 网站,CDN都是一个很大的提高,网站的静态文件(js,img,css)等,通过CDN缓存,物理上降低静态文件到用户的传输距离,减少中间路由,极大提高静态资源访问速度。目前各大云厂商都提供CDN加速或全站加速(更加智能的缓存,不只是静态文件)。
并发请求数优化、多域名
浏览器 | 并发请求限制 |
---|---|
IE 7 | 2 |
IE 8/9 | 6 |
IE 10 | 8 |
IE 11 | 13 |
Firefox | 6 |
Chrome | 6 |
Safari | 6 |
Opera | 6 |
iOS WebView | 6 |
Android WebView | 6 |
浏览器并发请求限制一般是6个http连接,单个域名限制并发请求 6 个资源。在连接限制下有两个优化方法:
尽量较少请求数量,考虑合并部分请求减少请求,以6个连接为限制(应用复杂时较难实现)
多域名请求资源,如图片可以使用img1.abc.com、img2.abc.com进行请求,避开单独域名限制,同步加载图片
浏览器缓存
http 请求头增加缓存字段,后台前端均可使用
字段 | 说明 | 标记端 |
---|---|---|
Expires | 资源的过期时间 | |
Cache-Control | 缓存控制字段,精确控制缓存策略 | |
If-Modified-Since | 资源最近修改时间 | 浏览器 |
Last-Modified | 资源最近修改时间 | 服务器 |
Etag | 资源标识 | 服务器 |
If-None-Match | 缓存资源标识 | 浏览器 |
后台缓存:部分资源不需要频繁请求,可以设置Cache-Control字段,避免前端频繁请求,如图片等资源
# Nginx 配置server { server_name localhost; listen 8000; location ~ ^/img/(\w+)$ { alias /var/lib/abc/image/$1.jpeg; default_type image/jpeg; add_header Cache-Control 600; }}
前端缓存:通常前端代码由自身开发代码和第三方库组成,自身代码经常改动,第三方库较少改动,可以通过分开webpack代码打包方式解决
Http2
http2 相比http1性能提高较大,通过压缩头部,保持连接等方式提高资源利用率,效果可参考这个网站
其他解决方案
为了充分分析加载优化方案,除了常规做法,这里汇总特定场景使用或者已经弃用的方案,补全文章完整性,这部分优化效果没有前面的方案明显。
require.ensure
与 import() 类似,webpack 1.x 官方提供的懒加载方案。已被 import() 语法取代了。弃用
preload
w3c新出的一个标准。利用link的rel属性来声明相关“proload",从而实现预加载的目的,如下:
<link rel="preload" href="/styles/other.css" as="style"><link rel="preload" href="example.js" as="script">
preload 关键字告知浏览器启用preload功能,浏览器检测到这个属性后,就会预先加载资源,目前兼容性较差。webpack 有相关插件,有兴趣可以尝试:preload-webpack-plugin
长页面滚动场景
通过监听滚动条,判断视图区域,只加载对应资源,如社交网站的评论区滚动,google 搜索 image 的滚动加载。
分页预加载
项目较多时通常采用分页方式提供用户浏览,如用户在浏览页面1的间隙,import() 等动态加载方式将第二页数据下载下来,用户点击下一页时可立即看到页面,用户体验较好。使用场景如:电商的商品页面。
Skeleton
事先撑开即将渲染的元素,避免闪屏,同时提示用户这要渲染东西,减少用户焦虑
https://github.com/lavas-project/vue-skeleton-webpack-plugin
发表评论 取消回复