提炼函数:避免出现超大函数,独立出来的函数更容易被复写且有利于代码复用
原则:多使用内存,缓存等其他方法、减少CPU计算量,减少网络加载耗时即用空间换时间的一个概念
让加载、渲染更快
加载:
- 减少资源体积:压缩代码
- 控制并发请求:减少访问次数:合并代码,SSR服务端渲染
- 使用更快的网络:CDN
渲染:
- 文件放置位置:css放head中,js放body下
- 懒加载:组件/路由的懒加载
- 缓存:对DOM查询进行缓存、频繁DOM操作,合并到一起插入DOM结构
- 节流和防抖
缓存策略:expires、Cache-Control、
Last-Modified/If-Modified-Since:本地缓存没有过期
Etag/f-None-Match:缓存过期了
webpack中使用contenthash:静态资源加hash后缀,根据文件内容计算hash,文件内容不变则hash、url不变、url和文件不变则会自动触发http缓存机制,返回304
Vue 代码层面的优化
合理使用v-if,v-show
合理使用computed
v-for中加key,避免与v-if同时使用
合理使用异步组件
合理使用缓存组件keep-alive
data层级不要太深:导致响应式在做监听时计算的深度比较多,定位的次数比较多,会导致页面卡顿
使用vue-loader在开发环境做模板编译?
长列表性能优化:Vue 会通过 Object.defineProperty 对数据进行劫持,来实现视图响应数据的变化,然而有些时候我们的组件就是纯粹的数据展示,不会有任何改变,我们就不需要 Vue 来劫持我们的数据,在大量数据展示的情况下,这能够很明显的减少组件初始化的时间,通过使用Object.freeze
export default { data: () => ({ users: {} }), async created() { const users = await axios.get("/api/users"); this.users = Object.freeze(users); }};
复制代码
自定义事件,DOM事件及时销毁:Vue 组件销毁时,会自动清理它与其它实例的连接,解绑它的全部指令及事件监听器,但是仅限于组件本身的事件。如果在 js 内使用 addEventListene 等方式是不会自动销毁的,我们需要在组件销毁时手动移除这些事件的监听,以免造成内存泄露
created() { addEventListener('click', this.click, false)},beforeDestroy() { removeEventListener('click', this.click, false)}
复制代码
使用路由懒加载:把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样就更加高效了。这样会大大提高首屏显示的速度,但是可能其他的页面的速度就会降下来
webpack 配置层面的优化
减少 ES6 转为 ES5 的冗余代码
Babel 插件会在将 ES6 代码转换成 ES5 代码时会注入一些辅助函数,例如下面的 ES6 代码:
class HelloWebpack extends Component{…}
这段代码再被转换成能正常运行的 ES5 代码时需要以下两个辅助函数:
babel-runtime/helpers/createClass // 用于实现 class 语法
babel-runtime/helpers/inherits // 用于实现 extends 语法
复制代码
默认情况下, Babel 会在每个输出文件中内嵌这些依赖的辅助函数代码,若多个源代码文件都依赖这些辅助函数,那辅助函数的代码将会出现很多次,造成代码冗余。为解决这个可以在依赖它们时通过
require(‘babel-runtime/helpers/createClass’) 的方式导入,
这样就能做到只让它们出现一次。babel-plugin-transform-runtime 插件就是用来实现这个作用的,将相关辅助函数进行替换成导入语句,从而减小 babel 编译出来的代码的文件大小,安装该插件后修改 .babelrc 配置文件为
“plugins”: [“transform-runtime”]
提取公共代码
如果项目中没有去将每个页面的第三方库和公共模块提取出来,则项目会存在以下问题:
- 相同的资源被重复加载,浪费用户的流量和服务器的成本。
- 每个页面需要加载的资源太大,导致网页首屏加载缓慢,影响用户体验
所以需要把公共的代码抽离成单独的文件,来优化以上问题,Webpack 内置了专门用于提取多个Chunk 中的公共部分的插件 CommonsChunkPlugin,项目中 CommonsChunkPlugin 的配置如下
优化 SourceMap
在项目进行打包后,会将开发中的多个文件代码打包到一个文件中,并且经过压缩、去掉多余的空格、babel编译化后,最终将编译得到的代码会用于线上环境,那么这样处理后的代码和源代码会有很大的差别,当有 bug的时候,我们只能定位到压缩处理后的代码位置,无法定位到开发环境中的代码,对于开发来说不好调式定位问题,因此 sourceMap 出现了,它就是为了解决不好调式代码问题的
- 开发环境推荐:cheap-module-eval-source-map
- 生产环境推荐:cheap-module-source-map
原因如下:
- cheap:源代码中的列信息是没有任何作用,因此我们打包后的文件不希望包含列相关信息,只有行信息能建立打包前后的依赖关系。因此不管是开发环境或生产环境,我们都希望添加 cheap 的基本类型来忽略打包前后的列信息;
- module :不管是开发环境还是正式环境,我们都希望能定位到bug的源代码具体的位置,比如说某个 Vue 文件报错了,我们希望能定位到具体的 Vue 文件,因此我们也需要 module 配置;
- soure-map :source-map 会为每一个打包后的模块生成独立的 soucemap 文件 ,因此我们需要增加source-map 属性;
- eval-source-map:eval 打包代码的速度非常快,因为它不生成 map 文件,但是可以对 eval 组合使用 eval-source-map 使用会将 map 文件以 DataURL 的形式存在打包后的 js 文件中。在正式环境中不要使用 eval-source-map, 因为它会增加文件的大小,但是在开发环境中,可以试用下,因为他们打包的速度很快
构建结果输出分析
Webpack 输出的代码可读性非常差而且文件非常大,让我们非常头疼。为了更简单、直观地分析输出结果,社区中出现了许多可视化分析工具。这些工具以图形的方式将结果更直观地展示出来,让我们快速了解问题所在。接下来讲解我们在 Vue 项目中用到的分析工具:webpack-bundle-analyzer
项目中 webpack.prod.conf.js 进行配置:
if (config.build.bundleAnalyzerReport) {
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
webpackConfig.plugins.push(new BundleAnalyzerPlugin());
}
复制代码
执行 $ npm run build –report 后生成分析报告如下
开启 gzip 压缩
compression-webpack-plugin、在webpack.prod.conf.js中的配置
配置完后执行build命令,会发现生成的静态文件里面新增了后缀为gz的文件
如果此时将项目部署到已开启了gzip的服务器如nginx里面之后,访问浏览器即可看到浏览器下载的是已压缩的文件
服务器配置gzip,只是为了可以兼容这种格式,可以读取这种格式,压缩为gzip还是需要前端做的2:服务器把gzip发送给浏览器,浏览器认识这种格式所以能解读他3:用处就是用户获取的文件体积减小了,下载的快了
基础的 Web 技术层面的优化
浏览器缓存
为了提高用户加载页面的速度,对静态资源进行缓存是非常必要的,根据是否需要重新向服务器发起请求来分类,将 HTTP 缓存规则分为两大类(强制缓存,对比缓存)
CDN的使用
浏览器从服务器上下载 CSS、js 和图片等文件时都要和服务器连接,而大部分服务器的带宽有限,如果超过限制,网页就半天反应不过来。而 CDN 可以通过不同的域名来加载文件,从而使下载文件的并发连接数大大增加,且CDN 具有更好的可用性,更低的网络延迟和丢包率
使用 Chrome Performance 查找性能瓶颈
Chrome 的 Performance 面板可以录制一段时间内的 js 执行细节及时间。使用 Chrome 开发者工具分析页面性能的步骤如下。
- 打开 Chrome 开发者工具,切换到 Performance 面板
- 点击 Record 开始录制
- 刷新页面或展开某个节点
- 点击 Stop 停止录制