vue - common performance optimization

insert image description here

Common performance optimizations in vue use


1, v-for traversal to avoid using v-if at the same time

In Vue2, v-forthe priority is higher, so during the compilation process, all list elements will be traversed to generate a virtual DOM, and then judged by v-if to render, there will be redundant logical judgments and waste of performance, because we want The most important thing is that virtual DOM that does not meet the conditions should not be generated;

1, in order to filter items in a list ( 比如 v-for="user in users" v-if="user.isActive"). In this case, users can be replaced with a computed property or method (such as activeUsers) that returns a filtered list;

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

methods:{
    
    
	// 方法
	activeUsers(){
    
    
		//在这里面处理需要显示的数据  然后返回筛选过的列表
	}
}

2. To avoid rendering a list that should be hidden ( 比如 v-for="user in users" v-if="shouldShowUsers"). In this case, move the v-if to the container element (eg ul, ol).

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

v-ifThe priority in Vue3 is higher, which means that when the judgment condition is an attribute in the list traversed by v-for, v-if cannot be obtained;

注意: Never use v-if and v-for on the same element at the same time.

2. If you need to use v-for to bind events to each element, you can use event proxy**

The essence of event delegation is to use the feature of event bubbling to parent elements. In this way, there is no need to add events to each node in the loop; as follows:

Add a click event on the parent element ul. If you need to pass parameters, you only need to add custom attributes, such as the id attribute below

  <!--  使用事件委托进行处理和传参 添加自定义属性id -->
    <ul class="weekdays" @click="debounce($event)">
      <li v-for="(item, index) in dayList" :key="index" :id="index" >{
    
    {
    
     item.day }}</li>
    </ul>

	// 事件委托处理
    debounce(event) {
    
    
      if (event.target && event.target.nodeName == "LI") {
    
    
        // 现在就可以拿到当前的节点 所以就能拿到里面的属性和数据
          console.log("我点击的是:", event.target);
      }
    },

There are two benefits of event proxy
: 1. Proxy the event handler to the parent node to reduce memory usage;
2. Automatically bind the event handler to the parent node when dynamically generating child nodes;

3. Some data is not responsive

Some data is not responsive, such as member lists, product lists, etc., but pure data display. In scenarios where there will not be any dynamic changes, there is no need to perform responsive processing on the data, which can greatly improve the rendering speed;

You can use Object.freeze()a method to freeze an object, and the object frozen by this method cannot be modified; that is, you cannot add new properties to this object, delete existing properties, or modify the enumerability, configurability, and writability of the existing properties of the object properties, and cannot modify the value of existing properties, and the prototype of the object cannot be modified;

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

Vue2's responsive source code address: src/core/observer/index.js - 144行it is like this:

export function defineReactive (...){
    
    
	// getOwnPropertyDescriptor 返回指定对象上一个自有属性对应的属性描述符
	// 也就是直接赋予该对象的属性,不需要从原型链上进行查找的属性
    const property = Object.getOwnPropertyDescriptor(obj, key)
    
	判断configurable``false`不做处理
    if (property && property.configurable === false) {
    
    
        return
    }
    ...
}

configurableIt can be seen that the direct return that is judged as at the beginning falsedoes not do responsive processing;

configurable``false` 表示这个属性是不能被修改的,而冻结的对象的 `configurable` 就是为 `false

This is the data that Vue normally defines in data, and it will automatically add get and set attributes to all the following attributes, as many as there are:

insert image description here

开始冻结对象

freList is the list data of the request backend;

  created() {
    
    
    this.dayList = Object.freeze(freList)
    console.log("daylist:",this.dayList);
  },

It can be seen that there are no get and set attributes, but at the same time these data are not responsive;

insert image description here

4. Some pages use keep-alivecaching components

For example, after the form input page enters the next step, and then returns to the previous step to the form page, the content of the form input should be retained, such as 列表页>详情页>列表页in the scene of jumping back and forth, etc.;

Basic use:

	如果需要缓存整个项目,则如下设置(直接包裹根router-view即可)<keep-alive>
    	<router-view> </router-view>
	</keep-alive>

	缓存部分页面或者组件,使用route.meta属性
	<keep-alive>
    	<router-view v-if="$route.meta.keepAlive"></router-view>
	</keep-alive>
    	<router-view v-if="!$route.meta.keepAlive"></router-view>


	注:<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
	<keep-alive>
    	<component :is="view"></component>
	</keep-alive> 

Note: A page configured with keepAlive will not be re-rendered when re-entered (all hook functions will be triggered when it is first entered), and the components in this page will not be re-rendered in the same way.

And this may cause related operations in the component (those operations that need to re-render the page every time: such as passing values ​​between parent and child components) no longer take effect. This may lead to some inexplicable and unverifiable bugs;

Vue2.1.0 added include and exclude attributes, which allow conditional caching of components. Both can be represented as a comma-separated string, a regular expression, or an array.

    <!-- 逗号分隔字符串 -->
    <keep-alive include="a,b">
        <component :is="view"></component>
    </keep-alive>
 
    <!-- 正则表达式 (需要 `v-bind`绑定) -->
	<keep-alive :include="/a|b/">
    	<component :is="view"></component>
	</keep-alive>
 
    <!-- 数组 (需要 `v-bind`绑定) -->
	<keep-alive :include="['a', 'b']">
    	<component :is="view"></component>
	</keep-alive>

Note: The matching first checks the name option of the component itself, and if the name option is not available, it matches its local registered name (the key value of the parent component components option). Anonymous components cannot be matched.

Dynamic judgment, use v-bind:include

<keep-alive :include="includedComponents">
    <router-view></router-view>
</keep-alive>

includedComponents动态设置即可  

Use beforeRouteLeave or afterEach for interception processing

如在项目在Category组件中的设置:
beforeRouteLeave(to,from,next){
    
    
    if(to.name=='DemoIndex'){
    
    
        if(!from.meta.keepAlive){
    
    
            from.meta.keepAlive=true
        }
        next()
    }else{
    
    
        from.meta.keepAlive=false
        to.meta.keepAlive=false
        next()
    }
},
在beforeRouteLeave中to.name根据具体的路由进行动态缓存设置

Life cycle changes after using keepAlive (important):

Enter the cache page for the first time: beforeRouteEnter --> created --> mounted --> activated --> deactivated
Enter the cache page again: beforeRouteEnter --> activated --> deactivated

Note:
1. The activated here is very useful, because when the page is cached, the created, mounted and other life cycles are invalid. If you want to perform some operations, you can complete it in activated (the following will give a chestnut: the list page returns to the top Second browsing position)
2. The activated keep-alive component is called when it is activated, and this hook is not called during server-side rendering.
3. The deactivated keep-alive component is called when it is deactivated. This hook is not called during server-side rendering.

5. Import third-party UI library on demand

For example, vantUi, the on-demand introduction of element-ui library; see this article

6. Lazy loading of list data and sliding loading of paging data

The lazy loading scroll bar of the list data starts to request the data of the next page when the scroll bar is scrolled to the bottom, try to use it with the anti-shake function to prevent too many requests in an instant.

如下代码

Here I use vue3 to write, vue2 is just a different way to get nodes, everything else is the same;

onMounted(() => {
    
    
   // 获取滚动容器的节点
  let containerEle = showContentEl.value;
  if (!containerEle) return;
  
  // 监听滚动条
  containerEle.addEventListener("scroll", function () {
    
    
    const clientHeight = containerEle.clientHeight;
    const scrollTop = parseInt(containerEle.scrollTop);
    const scrollHeight = containerEle.scrollHeight;
    // 判断是否滚动条是否滚动到底  (-1是为了控制误差)
    if (clientHeight + scrollTop >= scrollHeight - 1) {
    
    
      // 开始防抖请求数据
      debounceLoadMaterialList();
    }
  });
});

<template>
  <div class="container">
    <div class="list">
      	展示的列表数据
    </div>
  </div>
</template>

Set interface anti-shake:

import * as _ from "lodash";
// 设置接口防抖
const debounceLoadMaterialList = _.debounce(loadMaterialList, 500);

7. Variable localization

Simply put, it is to save the variables that will be referenced multiple times, because every this.xxtime you access , because it is a responsive object, it will be triggered every time getter, and then execute the relevant code that depends on the collection. If you use more variables, the performance will naturally improve. worse;

In terms of requirements, it is enough to perform a dependency collection on a variable in a function, but many people habitually write a lot in the project, this.xxignoring this.xxwhat is done behind the scenes, which will lead to performance problems;

比如下面vue2的例子

<template>
  <div :style="{ opacity: number / 100 }"> {
    
    {
    
     result }}</div>
</template>
<script>
import {
    
     someThing } from '@/utils'
export default {
    
    
  props: ['number'],
  computed: {
    
    
    base () {
    
     return 100 },
    result () {
    
    
    
      let base = this.base, number = this.number // 保存起来  -- 变量本地化
      for (let i = 0; i < 1000; i++) {
    
    
        number += someThing(base) // 避免频繁引用 this.xx
      }
      return number
    }
  }
}
</script>

8. Destruction of events

When a Vue component is destroyed, all its instructions and event listeners will be automatically unbound, but only limited to the events of the component itself;

For 定时器registered addEventListenerlisteners, etc., they need to be manually destroyed or unbound in the lifecycle hook of component destruction to avoid memory leaks;

<script>
export default {
    
    
    created() {
    
    
      this.timer = setInterval(this.refresh, 2000)
      addEventListener('touchmove', this.touchmove, false)
    },
    beforeDestroy() {
    
    
      clearInterval(this.timer)
      this.timer = null
      removeEventListener('touchmove', this.touchmove, false)
    }
}
</script>

Guess you like

Origin blog.csdn.net/qq_43886365/article/details/131766043
Recommended