美文网首页高级js用法Vue
九种Vue性能优化方法

九种Vue性能优化方法

作者: SCQ000 | 来源:发表于2020-03-29 12:35 被阅读0次

    Vue前端开发到第一阶段,就要开始考虑性能优化相关的要点了。这也是用来判断一名前端的水平是否优秀的一个标准。接下来这篇文章,将介绍几种在实践过程中可以用到的性能优化技巧(文中例子来自https://www.youtube.com/watch?v=5B66qer8cZo)。

    函数型组件

    由于组件的生命周期处理在框架层面上十分耗时,所以,建议平常尽量使用函数型组件。这样,可以避免不必要的性能损失。只要在模板上声明functional属性,就可以实现函数式组件了:

    <template functional>
        <div>
            <div v-if="value" class="on"></div>
            <section v-else class="off"></section>
        </div>
    </template>
    
    <script>
        export default {
            props: ['value']
        }
    </script>
    

    子组件拆分

    另一个优化技巧是,将复杂的耗时计算处理放在子组件中进行处理:

    <template>
        <div :style="{opacity: number / 300 }">
            <ChildComp />
        </div>
    </template>
    
    <script>
        export default {
            props: ['number'],
            components: {
                ChilComp: {
                    methods: {
                        heavy() {
                            // heavy task
                        }
                    },
                    render(h) {
                        return h('div', this.heavy())
                    }
                }
            }
        }
    </script>
    

    局部变量

    平常在引用computed数据进行计算的时候,可以多使用局部变量,这样可以避免多次重复计算。

    <template>
      <div :style="{ opacity: start / 300 }">{{ result }}</div>
    </template>
    
    <script>
    export default {
      props: ['start'],
      computed: {
        base () {
          return 42
        },
        result () {
          // 赋值给局部变量,防止重复计算
          const base = this.base;
          let result = start
          for (let i = 0; i < 1000; i++) {
            result += Math.sqrt(Math.cos(Math.sin(base))) + base * base + base + base * 2 + base * 3
          }
          return result
        },
      },
    }
    </script>
    

    活用v-show,减少v-if

    对于需要频繁切换的视图来说,使用v-showv-if更加节约性能。因为v-show可以避免dom节点的销毁和重建,所以我们可以将如下的例子

    <template functional>
        <div class="cell">
            <div v-if="props.value" class="on">
                <Heavy :n="10000" />
            </div>
            <section v-else class="off">
                <Heavy :n="10000" />
            </section>
        </div>
    </template>
    

    改写为

    <template functional>
        <div class="cell">
            <div v-show="props.value" class="on">
                <Heavy :n="10000" />
            </div>
            <section v-show="!props.value" class="off">
                <Heavy :n="10000" />
            </section>
        </div>
    </template>
    

    使用keep-alive

    另外一种很常用的优化技巧是使用keep-alive,通常是在路由切换组件中使用:

    <template>
        <div id="app">
            <keep-alive>
                <router-view />
            </keep-alive>
        </div>
    </template>
    

    使用keep-alive后,可以保留组件状态并且避免重新渲染。

    活用延迟加载(defer)

    <template>
      <div class="deferred-off">
        <VueIcon icon="fitness_center" class="gigantic"/>
    
        <h2>I'm an heavy page</h2>
    
        <Heavy v-for="n in 8" :key="n"/>
    
        <Heavy class="super-heavy" :n="9999999"/>
      </div>
    </template>
    
    <template>
      <div class="deferred-on">
        <VueIcon icon="fitness_center" class="gigantic"/>
    
        <h2>I'm an heavy page</h2>
    
        <template v-if="defer(2)">
          <Heavy v-for="n in 8" :key="n"/>
        </template>
    
        <Heavy v-if="defer(3)" class="super-heavy" :n="9999999"/>
      </div>
    </template>
    
    <script>
    import Defer from '@/mixins/Defer'
    export default {
      mixins: [
        Defer(),
      ],
    }
    </script>
    

    分批处理(time slicing)

    下面这个性能优化的点是前端通用的,可以用requestAnimationFrame分批次执行大数据量的计算,防止一次性执行的数据太大从而阻塞页面渲染。

    比如下面这个例子:

    fetchItems({ commit }, { items }) {
        commit('clearItems');
        commit('addItems', items)
    }
    

    可以改写为:

    fetchItems({ commit }, { items, splitCount }) {
        commit('clearItems');
        //新建一个队列
        const queue = new JobQueue();
        splitArray(items, splitCount).forEach(chunk => queue.addJob(done => {
            // 分片
            requestAnimationFrame(() => {
                commit('addItems', chunk);
                done()
            });
        }));
        
        // 等待所有数据处理完毕
        awiat queue.start();
    }
    

    非响应式模式(non-reactive)

    对于复杂的数据结构,我们可以显式声明为非响应式,这样可以避免很多不必要的计算,从而提高性能:

    const data = items.map(item => optimizeItem(item));
    
    function optimizeItem (item) {
        const itemData = {
            id: uid ++,
            vote: 0
        };
        Object.defineProperty(itemData, 'data', {
            // mark as non-reactive
            configurable: false,
            value: item
        });
        return itemData
    }
    

    仅渲染可视化部分

    对于无限长列表来说,性能优化主要方法是保持仅渲染可视化部分。

    来看一下下面这个例子:

    <div class="items no-v">
        <FetchItemViewFunctional v-for="item of items" :key="item.id" :item="item" @vote="voteItem(item)">
        </FetchItemViewFunctional>
    </div>
    

    这是最常见的写法,不过如果列表的内容很多,你就会发现页面十分的卡顿。此时大家可以利用vue-virtual-scroller这个组件,进行优化:

    <recycle-scroller
        class="item"
        :items="items"
        :item-size="24"              
    >
        <template v-slot="{item}">
            <FetchItemView :item="item" @vote="voteItem(item)"/>
        </template>
    </recycle-scroller>
    

    这样,可以大大提升组件的流畅度和性能。

    ——本文首发于个人公众号,转载请注明出处———

    微信扫描二维码,关注我的公众号

    最后,欢迎大家关注我的公众号,一起学习交流。

    参考资料

    https://www.youtube.com/watch?v=5B66qer8cZo

    相关文章

      网友评论

        本文标题:九种Vue性能优化方法

        本文链接:https://www.haomeiwen.com/subject/degoyhtx.html