Skip to content

使用冻结对象提升效率(Vue2)


先看一段代码:

点击load list按钮,往list中添加1000000条数据

vue
<template>
  <div id="app">
    <button @click="loadList">load list</button>
    <h1>list count: {{ list.length }}</h1>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: []
    };
  },
  methods: {
    loadList() {
      this.list = this.getList();
    },
    getList() {
      const result = [];
      for (let i = 0; i < 1000000; i++) {
        result.push({
          id: i,
          name: `name${i}`,
          address: {
            city: `city${i}`,
            province: `province${i}`
          }
        });
      }
      return result;
    }
  }
};
</script>

<style>
#app {
  text-align: center;
}
</style>

问题:

点击load list按钮之后的结果:

result view

通过录制工具可以看到,js执行时间有4109ms,而渲染并没有花费时间(首先页面没有几个元素,其次计算机执行时间是以纳秒为单位,这里显示0是因为小于了1ms

result view

了解过vue2响应式原理的都知道,vue2的响应式系统是通过深度遍历数据,利用Object.defineProperty为所有属性添加gettersetter方法,所以时间主要的损耗就在vue将数据转为响应式数据的过程。

但是有些时候,我们并不需要数据响应式,比如纯展示型的列表。那么我们就需要告诉vue,这个时候,就可以使用冻结对象: Object.freeze()

TIP

Object.freeze()静态方法可以使一个对象被冻结。冻结对象可以防止扩展,并使现有的属性不可写入和不可配置。被冻结的对象不能再被更改:不能添加新的属性,不能移除现有的属性,不能更改它们的可枚举性、可配置性、可写性或值,对象的原型也不能被重新指定。freeze() 返回与传入的对象相同的对象。

当我们给vue的数据赋值新数据的时候,vue内部会通过Object.isFrozen进行判断,判断是否为冻结对象,如果是,vue将不再为此数据添加响应式方法。

优化:

vue
<template>
  <div id="app">// ...</div>
</template>

<script>
export default {
  data() {
    return {
      list: []
    };
  },
  methods: {
    loadList() {
      this.list = Object.freeze(this.getList()); 
    },
    getList() {
      // ...
    }
  }
};
</script>

效果:

result view

可以看到js执行时间已经大幅缩减!!!

总结

虽然我们通过Object.freeze()方法提升了页面的响应速度,但同时我们也失去了数据响应式的功能。所以说优化并不是一概而论的,一定是因地制宜,具体情况具体分析。