vue功能优化 – 实践攻略

一、代码层面的优化

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 内运用 addEventListene 等方法是不会主动毁掉的,咱们需求在组件毁掉时手动移除这些事情的监听,以免构成内存泄露,如:

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 ,从而将图片显现方法更改为懒加载显现:

<img v-lazy="/static/img/1.png">

以上为 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 代表中等速度 )

vue - 性能优化

开发环境引荐: 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 后生成剖析陈述如下:

vue - 性能优化

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 敞开成功 :
    vue - 性能优化

3.2、浏览器缓存

为了进步用户加载页面的速度,对静态资源进行缓存是十分必要的,依据是否需求从头向服务器发起恳求来分类,将 HTTP 缓存规则分为两大类(强制缓存,比照缓存),假如对缓存机制还不是了解很清楚的,能够参阅作者写的关于 HTTP 缓存的文章《深化了解HTTP缓存机制及原理》,这儿不再赘述。

3.3、CDN 的运用

浏览器从服务器上下载 CSS、js 和图片等文件时都要和服务器衔接,而大部分服务器的带宽有限,假如超越约束,网页就半响反应不过来。而 CDN 能够经过不同的域名来加载文件,从而使下载文件的并发衔接数大大增加,且CDN 具有更好的可用性,更低的网络推迟和丢包率 。

3.4、运用 Chrome Performance 查找功能瓶颈

Chrome 的 Performance 面板能够录制一段时刻内的 js 履行细节及时刻。运用 Chrome 开发者东西剖析页面功能的过程如下。

  1. 打开 Chrome 开发者东西,切换到 Performance 面板
  2. 点击 Record 开端录制
  3. 刷新页面或展开某个节点
  4. 点击 Stop 中止录制

vue - 性能优化

更多关于 Performance 的内容能够点击这儿检查。