从性能角度看vue component是否拆分

1,538 阅读2分钟

前言

面对一个功能的实现是把分成几个组件,还是不分呢,这是个问题?对于是否要拆分,我列了些常见的理由如下:

  1. 更好的复用代码
  2. 降低组件的复杂度(毕竟没人想看几百行代码的组件)
  3. 测试更方便些
  4. ...

然而我想说的是,对于vue的组件来说,拆分组件可能会带来性能优化

一个问题

来看一个简单的组件(代码如下), 在input框输入数字1,页面会有什么样的变化?

<template>
  <div>
    <div>{{ curText }}</div>
    <input type="text" v-model="curText" />
    <div v-for="curItem in 100" :key="curItem">
      {{ curItem }}
      <div v-for="curItem1 in 50" :key="curItem1">
        {{ curItem1 }}
        <div v-for="curItem2 in 50" :key="curItem2">
          {{ curItem2 }}
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      curText: "",
    };
  },
};
</script>

答案是会在页面显示出1, 完了??? 确实,但是出现1的过程确有些卡 (如下图所示)

ezgif-6-2d664e49cff5.gif

上面这种情况出现卡顿,在分析原因之前,将这个组件进行拆分,过程如下

  • 将上面页面中不改变的部分抽成一个单独组件
displayComponent.vue

<template>
    <div>
        <div v-for="curItem in 100" :key="curItem">
            {{ curItem }}
            <div v-for="curItem in 50" :key="curItem">
                {{ curItem }}
                <div v-for="curItem in 50" :key="curItem">
                {{ curItem }}
                </div>
            </div>
        </div>
    </div>
</template>
原本代码则改成如下

<template>
  <div>
    <div>{{ curText }}</div>
    <input type="text" v-model="curText" />
    <display-componet></display-componet>
  </div>
</template>

改完再次输入1时,就会发现卡的现象消失了(或者说好多了)!!!!!

简单的分析

通过对比两次的改动可以明显的发现

  • 改动的地方只是将页面中不变的部分抽成了组件
  • 整个页面的dom数据很多

那根据上面的例子和简单,很容易得出一个结论抽成一个组件(数据无依赖)对页面性能是有帮助的。同时也很容易产生一个疑问-》这个是为啥呢??

为了解决疑问,让我们看看在往input里输入数字,vue做了什么事

输入数字1 =》 ... 触发_update => patch => patchVnode => updateChidren ...

上面的写出的部分流程也就是耳熟能详的virtual dom diff部分过程 (关于diff算法及具体流程这里就不再赘述,有许多优秀文章讲解),在这个过程中可以发现updateChildren对于有没拆分组件有着巨大的差异:

拆成组件不拆组件
updateChidren没有会遍历检测所有子节点(重复patchVnode 步骤)

当dom节点足够多的时候,遍历检测节点也就大量的时间消耗

结论

通过上述的例子,也就说明了有时候拆分成组件会带来性能的优化, 当然这不是绝对的,例如:有数据关联的父子组件 (以上的例子都是在vue 2.6的版本)

最后上述有任何不正确的地方,欢迎指出,感谢!!