关于vue.js:vue项目性能优化前端加分项

7次阅读

共计 8633 个字符,预计需要花费 22 分钟才能阅读完成。

前言

Vue 框架通过数据双向绑定和虚构 DOM 技术,帮咱们解决了前端开发中最脏最累的 DOM 操作局部,咱们不再须要去思考如何操作 DOM 以及如何最高效地操作 DOM;但 Vue 我的项目中依然存在我的项目首屏优化、Webpack 编译配置优化等问题,所以咱们依然须要去关注 Vue 我的项目性能方面的优化,使我的项目具备更高效的性能、更好的用户体验。本文是作者通过理论我的项目的优化实际进行总结而来,心愿读者读完本文,有肯定的启发思考,从而对本人的我的项目进行优化起到帮忙。本文内容分为以下三局部组成:

Vue 代码层面的优化;

webpack 配置层面的优化;

根底的 Web 技术层面的优化。

一、代码层面的优化

1.1、v-if 和 v-show 辨别应用场景

v-if 是 真正 的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

v-show 就简略得多,不论初始条件是什么,元素总是会被渲染,并且只是简略地基于 CSS 的 display 属性进行切换。

所以,v-if 实用于在运行时很少扭转条件,不须要频繁切换条件的场景;v-show 则实用于须要十分频繁切换条件的场景。

1.2、computed 和 watch 辨别应用场景

computed:是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值产生扭转,下一次获取 computed 的值时才会从新计算 computed 的值;

watch:更多的是「察看」的作用,相似于某些数据的监听回调,每当监听的数据变动时都会执行回调进行后续操作;

使用场景:

当咱们须要进行数值计算,并且依赖于其它数据时,应该应用 computed,因为能够利用 computed 的缓存个性,防止每次获取值时,都要从新计算;

当咱们须要在数据变动时执行异步或开销较大的操作时,应该应用 watch,应用 watch 选项容许咱们执行异步操作 (拜访一个 API),限度咱们执行该操作的频率,并在咱们失去最终后果前,设置中间状态。这些都是计算属性无奈做到的。

1.3、v-for 遍历必须为 item 增加 key,且防止同时应用 v-if

(1)v-for 遍历必须为 item 增加 key

在列表数据进行遍历渲染时,须要为每一项 item 设置惟一 key 值,不便 Vue.js 外部机制精准找到该条列表数据。当 state 更新时,新的状态值和旧的状态值比照,较快地定位到 diff。

(2)v-for 遍历防止同时应用 v-if

v-for 比 v-if 优先级高,如果每一次都须要遍历整个数组,将会影响速度,尤其是当之须要渲染很小一部分的时候,必要状况下应该替换成 computed 属性。

举荐:

<ul>
  <li
    v-for="user in activeUsers"
    :key="user.id">
    {{user.name}}  </li>
</ul>
computed: {activeUsers: function () {return this.users.filter(function (user) {return user.isActive})
  }
}

不举荐:

<ul>
  <li
    v-for="user in users"
    v-if="user.isActive"
    :key="user.id">
    {{user.name}}
  </li>
</ul>

1.4、长列表性能优化

Vue 会通过 Object.defineProperty 对数据进行劫持,来实现视图响应数据的变动,然而有些时候咱们的组件就是纯正的数据展现,不会有任何扭转,咱们就不须要 Vue 来劫持咱们的数据,在大量数据展现的状况下,这可能很显著的缩小组件初始化的工夫,那如何禁止 Vue 劫持咱们的数据呢?能够通过 Object.freeze 办法来解冻一个对象,一旦被解冻的对象就再也不能被批改了。

export default {data: () => ({users: {}
  }),
  async created() {const users = await axios.get("/api/users");
    this.users = Object.freeze(users);
  }
};

1.5、事件的销毁

Vue 组件销毁时,会主动清理它与其它实例的连贯,解绑它的全副指令及事件监听器,然而仅限于组件自身的事件。如果在 js 内

created() {addEventListener('click', this.click, false)
},
beforeDestroy() {removeEventListener('click', this.click, false)
}

1.6、图片资源懒加载

对于图片过多的页面,为了减速页面加载速度,所以很多时候咱们须要将页面内未呈现在可视区域内的图片先不做加载,等到滚动到可视区域后再去加载。这样对于页面加载性能上会有很大的晋升,也进步了用户体验。咱们在我的项目中应用 Vue 的 vue-lazyload 插件:

(1)装置插件

    npm install vue-lazyload --save-dev

(2)在入口文件 man.js 中引入并应用

import VueLazyload from 'vue-lazyload'

而后再 vue 中间接应用

Vue.use(VueLazyload)

或者增加自定义选项

Vue.use(VueLazyload, {
preLoad: 1.3,
error: 'dist/error.png',
loading: 'dist/loading.gif',
attempt: 1
})

(3)在 vue 文件中将 img 标签的 src 属性间接改为 v-lazy,从而将图片显示方式更改为懒加载显示:

以上为 vue-lazyload 插件的简略应用,如果要看插件的更多参数选项,能够查看 vue-lazyload 的 github 地址。

1.7、路由懒加载 Vue 是单页面利用,可能会有很多的路由引入,这样应用 webpcak 打包后的文件很大,当进入首页时,加载的资源过多,页面会呈现白屏的状况,不利于用户体验。如果咱们能把不同路由对应的组件宰割成不同的代码块,而后当路由被拜访的时候才加载对应的组件,这样就更加高效了。这样会大大提高首屏显示的速度,然而可能其余的页面的速度就会降下来。

路由懒加载:

const Foo = () => import('./Foo.vue')
const router = new VueRouter({
  routes: [{ path: '/foo', component: Foo}
  ]
})

1.8、第三方插件的按需引入

咱们在我的项目中常常会须要引入第三方插件,如果咱们间接引入整个插件,会导致我的项目的体积太大,咱们能够借助 babel-plugin-component,而后能够只引入须要的组件,以达到减小我的项目体积的目标。以下为我的项目中引入 element-ui 组件库为例:

(1)首先,装置 babel-plugin-component:

npm install babel-plugin-component -D

(2)而后,将 .babelrc 批改为:

{"presets": [["es2015", { "modules": false}]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

(3)在 main.js 中引入局部组件:

import Vue from 'vue';
import {Button, Select} from 'element-ui';

 Vue.use(Button)
 Vue.use(Select)

1.9、优化有限列表性能

如果你的利用存在十分长或者有限滚动的列表,那么须要采纳 窗口化 的技术来优化性能,只须要渲染少部分区域的内容,缩小从新渲染组件和创立 dom 节点的工夫。你能够参考以下开源我的项目 vue-virtual-scroll-list 和 vue-virtual-scroller 来优化这种有限列表的场景的。

1.10、服务端渲染 SSR or 预渲染

服务端渲染是指 Vue 在客户端将标签渲染成的整个 html 片段的工作在服务端实现,服务端造成的 html 片段间接返回给客户端这个过程就叫做服务端渲染。

(1)服务端渲染的长处:

更好的 SEO:因为 SPA 页面的内容是通过 Ajax 获取,而搜索引擎爬取工具并不会期待 Ajax 异步实现后再抓取页面内容,所以在 SPA 中是抓取不到页面通过 Ajax 获取到的内容;而 SSR 是间接由服务端返回曾经渲染好的页面(数据曾经蕴含在页面中),所以搜索引擎爬取工具能够抓取渲染好的页面;

更快的内容达到工夫(首屏加载更快):SPA 会期待所有 Vue 编译后的 js 文件都下载实现后,才开始进行页面的渲染,文件下载等须要肯定的工夫等,所以首屏渲染须要肯定的工夫;SSR 间接由服务端渲染好页面间接返回显示,无需期待下载 js 文件及再去渲染等,所以 SSR 有更快的内容达到工夫;

(2)服务端渲染的毛病:

更多的开发条件限度:例如服务端渲染只反对 beforCreate 和 created 两个钩子函数,这会导致一些内部扩大库须要非凡解决,能力在服务端渲染应用程序中运行;并且与能够部署在任何动态文件服务器上的齐全动态单页面应用程序 SPA 不同,服务端渲染应用程序,须要处于 Node.js server 运行环境;

更多的服务器负载:在 Node.js 中渲染残缺的应用程序,显然会比仅仅提供动态文件的 server 更加大量占用 CPU 资源,因而如果你意料在高流量环境下应用,请筹备相应的服务器负载,并明智地采纳缓存策略。

如果你的我的项目的 SEO 和 首屏渲染是评估我的项目的要害指标,那么你的我的项目就须要服务端渲染来帮忙你实现最佳的初始加载性能和 SEO,具体的 Vue SSR 如何实现,能够参考作者的另一篇文章《Vue SSR 踩坑之旅》。如果你的 Vue 我的项目只需改善多数营销页面(例如 /,/about,/contact 等)的 SEO,那么你可能须要预渲染,在构建时 (build time) 简略地生成针对特定路由的动态 HTML 文件。长处是设置预渲染更简略,并能够将你的前端作为一个齐全动态的站点,具体你能够应用 prerender-spa-plugin 就能够轻松地增加预渲染。

二、Webpack 层面的优化

2.1、Webpack 对图片进行压缩

在 vue 我的项目中除了能够在 webpack.base.conf.js 中 url-loader 中设置 limit 大小来对图片解决,对小于 limit 的图片转化为 base64 格局,其余的不做操作。所以对有些较大的图片资源,在申请资源的时候,加载会很慢,咱们能够用 image-webpack-loader 来压缩图片:

(1)首先,装置 image-webpack-loader:

npm install image-webpack-loader --save-dev

(2)而后,在 webpack.base.conf.js 中进行配置:

{test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  use:[
    {
    loader: 'url-loader',
    options: {
      limit: 10000,
      name: utils.assetsPath('img/[name].[hash:7].[ext]')
      }
    },
    {
      loader: 'image-webpack-loader',
      options: {bypassOnDebug: true,}
    }
  ]
}

2.2、缩小 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 编译进去的代码的文件大小。

(1)首先,装置 babel-plugin-transform-runtime:

npm install babel-plugin-transform-runtime --save-dev

(2)而后,批改 .babelrc 配置文件为:

"plugins": ["transform-runtime"]

如果要看插件的更多具体内容,能够查看 babel-plugin-transform-runtime 的 具体介绍。

2.3、提取公共代码

如果我的项目中没有去将每个页面的第三方库和公共模块提取进去,则我的项目会存在以下问题:

雷同的资源被反复加载,节约用户的流量和服务器的老本。

每个页面须要加载的资源太大,导致网页首屏加载迟缓,影响用户体验。

所以咱们须要将多个页面的公共代码抽离成独自的文件,来优化以上问题。Webpack 内置了专门用于提取多个 Chunk 中的公共局部的插件 CommonsChunkPlugin,咱们在我的项目中 CommonsChunkPlugin 的配置如下:

// 所有在 package.json 外面依赖的包,都会被打包进 vendor.js 这个文件中。

new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  minChunks: function(module, count) {
    return (
      module.resource &&
      /\.js$/.test(module.resource) &&
      module.resource.indexOf(path.join(__dirname, '../node_modules')
      ) === 0
    );
  }
}),
// 抽取出代码模块的映射关系
new webpack.optimize.CommonsChunkPlugin({
  name: 'manifest',
  chunks: ['vendor']
})

如果要看插件的更多具体内容,能够查看 CommonsChunkPlugin 的 具体介绍。

2.4、模板预编译

当应用 DOM 内模板或 JavaScript 内的字符串模板时,模板会在运行时被编译为渲染函数。通常状况下这个过程曾经足够快了,但对性能敏感的利用还是最好防止这种用法。

预编译模板最简略的形式就是应用单文件组件——相干的构建设置会主动把预编译解决好,所以构建好的代码曾经蕴含了编译进去的渲染函数而不是原始的模板字符串。

如果你应用 webpack,并且喜爱拆散 JavaScript 和模板文件,你能够应用 vue-template-loader,它也能够在构建过程中把模板文件转换成为 JavaScript 渲染函数。

2.5、提取组件的 CSS

当应用单文件组件时,组件内的 CSS 会以 style 标签的形式通过 JavaScript 动静注入。这有一些小小的运行时开销,如果你应用服务端渲染,这会导致一段“无款式内容闪动 (fouc)”。将所有组件的 CSS 提取到同一个文件能够防止这个问题,也会让 CSS 更好地进行压缩和缓存。

查阅这个构建工具各自的文档来理解更多:

webpack + vue-loader (vue-cli 的 webpack 模板曾经事后配置好)

Browserify + vueify

Rollup + rollup-plugin-vue

2.6、优化 SourceMap

咱们在我的项目进行打包后,会将开发中的多个文件代码打包到一个文件中,并且通过压缩、去掉多余的空格、babel 编译化后,最终将编译失去的代码会用于线上环境,那么这样解决后的代码和源代码会有很大的差异,当有 bug 的时候,咱们只能定位到压缩解决后的代码地位,无奈定位到开发环境中的代码,对于开发来说不好调式定位问题,因而 sourceMap 呈现了,它就是为了解决不好调式代码问题的。

SourceMap 的可选值如下(+ 号越多,代表速度越快,- 号越多,代表速度越慢, o 代表中等速度)

开发环境举荐: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, 因为它会减少文件的大小,然而在开发环境中,能够试用下,因为他们打包的速度很快。

2.7、构建后果输入剖析

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 后生成剖析报告如下:

2.8、Vue 我的项目的编译优化

如果你的 Vue 我的项目应用 Webpack 编译,须要你喝一杯咖啡的工夫,那么兴许你须要对我的项目的 Webpack 配置进行优化,进步 Webpack 的构建效率。具体如何进行 Vue 我的项目的 Webpack 构建优化,能够参考作者的另一篇文章《Vue 我的项目 Webpack 优化实际》

三、根底的 Web 技术优化

3.1、开启 gzip 压缩

gzip 是 GNUzip 的缩写,最早用于 UNIX 零碎的文件压缩。HTTP 协定上的 gzip 编码是一种用来改良 web 应用程序性能的技术,web 服务器和客户端(浏览器)必须独特反对 gzip。目前支流的浏览器,Chrome,firefox,IE 等都反对该协定。常见的服务器如 Apache,Nginx,IIS 同样反对,gzip 压缩效率十分高,通常能够达到 70% 的压缩率,也就是说,如果你的网页有 30K,压缩之后就变成了 9K 左右

以下咱们以服务端应用咱们相熟的 express 为例,开启 gzip 非常简单,相干步骤如下:

装置:

npm install compression –save
增加代码逻辑:

var compression = require('compression');
var app = express();
app.use(compression())

重启服务,察看网络面板外面的 response header,如果看到如下红圈里的字段则表明 gzip 开启胜利:

3.2、浏览器缓存

为了进步用户加载页面的速度,对动态资源进行缓存是十分必要的,依据是否须要从新向服务器发动申请来分类,将 HTTP 缓存规定分为两大类(强制缓存,比照缓存),如果对缓存机制还不是理解很分明的,能够参考作者写的对于 HTTP 缓存的文章《深刻了解 HTTP 缓存机制及原理》,这里不再赘述。

3.3、CDN 的应用

浏览器从服务器上下载 CSS、js 和图片等文件时都要和服务器连贯,而大部分服务器的带宽无限,如果超过限度,网页就半天反馈不过去。而 CDN 能够通过不同的域名来加载文件,从而使下载文件的并发连接数大大增加,且 CDN 具备更好的可用性,更低的网络提早和丢包率。

3.4、应用 Chrome Performance 查找性能瓶颈

Chrome 的 Performance 面板能够录制一段时间内的 js 执行细节及工夫。应用 Chrome 开发者工具剖析页面性能的步骤如下。

关上 Chrome 开发者工具,切换到 Performance 面板

点击 Record 开始录制

刷新页面或开展某个节点

点击 Stop 进行录制

正文完
 0