vue2性能优化之Object.freeze()测试

2,423 阅读2分钟

这是我参与8月更文挑战的第3天,活动详情查看: 8月更文挑战


前言

    今天在跟小伙伴过一个中奖名单h5活动Code Review时突然想起了一道面试题:在vue2.x中Object.defineProperty()的劣势都有哪些?,其中有一条答案就是object.defineProperty()会对data中所有的属性进行劫持增加get和set方法,即使这些属性不会触发视图响应。     而Object.freeze()可以冻结一个对象,对象冻结后就可以阻止对其数据劫持,减少数据的响应提升一部分性能。

Object.freeze()

Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。

  • Object.freeze()冻结的是值,直接对对象重新赋值修改其引用还是会改变;

  • 如果被冻结对象的value值还是引用类型,则无法冻结,需要冻结其value值,下面例子中对objobj.name冻结,修改obj.age下面的属性依旧生效,但是对被冻结的obj.name下的属性修改已经不生效了。

        var obj = {
            name: {
                firstName: "三",
                lastName: "张"
            },
            age: {
                nowAge: 16
            }
        };
        Object.freeze(obj);
        Object.freeze(obj.name);
        obj.name.firstName = '四';
        obj.age.nowAge = 17;
        console.log(obj.name.firstName)  //三
        console.log(obj.age.nowAge)  //17

性能测试

以一个10000条数据的列表为例,分别获取到数据改变前以及数据开始渲染视图,视图更新完成这三个点的时间戳,取其时间差。

系统: macos 10.15.6
环境: Chrome 92.0.4515.107
Vue: 2.5.2

<template>
  <div>
    <button @click="initList">重新加载</button>

    <table border="1" cellspacing="0" cellpadding="0">
      <thead>
        <tr>
          <td>序号</td>
          <td>昵称</td>
          <td>手机号</td>
          <td>礼品</td>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(item,index) in list" :key="index">
          <td>{{item.id+1}}</td>
          <td>{{item.name}}</td>
          <td>{{item.mobile}}</td>
          <td>{{item.prize}}</td>
        </tr>
      </tbody>
    </table>
  </div>
</template>
<script>
let t = 0
let t1 = 0
export default {
  name: 'list',
  data() {
    return {
      list: []
    }
  },
  created() {
    this.initList()
  },
  beforeUpdate() {
    t1 = new Date().getTime()
    console.log(t1 - t, "beforeUpdate时间差")
  },
  updated() {
    let time = new Date().getTime()
    console.log(time - t1, "updated时间差")
  },
  methods: {
    // 生成随机昵称
    getWord() {
      var _rsl = ""
      var _randomUniCode = Math.floor(Math.random() * (40870 - 19968) + 19968).toString(16)
      eval("_rsl=" + '"\\u' + _randomUniCode + '"')
      _rsl += ["先生", "女士"][Math.round(Math.random())]
      return _rsl
    },
    // 生成随机手机号
    getMobile() {
      var arr = new Array("130", "131", "132", "133", "135", "137", "138", "170", "187", "189")
      var i = parseInt(10 * Math.random())
      var mobile = arr[i]
      for (var j = 0; j < 8; j++) {
        mobile = mobile + Math.floor(Math.random() * 10)
      }
      return mobile
    },
    initList() {
      let list = []
      for (let i = 0; i < 10000; i++) {
        list.push({
          id: i,
          name: this.getWord(),
          mobile: this.getMobile(),
          prize: "500积分"
        })
      }
      t = new Date().getTime()
      this.list = list
    }
  }
}
</script>
<style scoped>
table {
  width: 100%;
}
</style>

多次执行得到大概如下结果: 1.png 再来修改this.list的赋值语句,改为freeze赋值

// this.list = list
this.list = Object.freeze(list)

可以看到Object.freeze()冻结后的list执行时间短于前者。数据量越大差距越明显。 2.png

结论

    综上,当在vue2中 data内的数据仅用来展示,不会对其修改时;或者只用于js内逻辑处理,不会对其进行操作时,可以使用Object.freeze()冻结这些数据,节省一部分性能。