灵活使用冻结对象提升代码效率,原理又是什么呢?

大家好,我是渡一前端子辰老师。

众所周知,前端开发是一个不断追求优化的领域,无论是在代码质量、性能效率还是用户体验方面,都需要不断地探索和创新。

今天我们以 Vue 为例,介绍一个常见的前端优化问题:如何避免不必要的数据响应式处理,从而提升页面的加载速度和运行效率。

通过对比实验和代码分析,展示使用冻结对象(Object.freeze)的方法优化,从而有效地减少数据响应式处理的时间消耗,同时也会指出这种方法的局限性和适用场景。

优化

我们来看一个 Vue 的优化问题。

下面代码中有一个按钮,调用一个 loadDatas 函数,loadDatas 函数中调用 getDatas 函数并获得生成的 100 万条数据,然后保存到变量 datas 上。

datas 的变化会引起页面的重新渲染。

<template>
<div id="app">
<button @click="loadDatas">loadDatas</button>
<h1>datas length:{{ datas.length }}</h1>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
datas: []
}
},
methods: {
loadDatas() {
this.datas = this.getDatas()
},
getDatas() {
const result = []
for (let i = 0; i < 1000000; i++) {
result.push({
id: i,
info: {
avatar: `avatar${i}`,
name: `name${i}`,
age: `age${i}`,
job: `job${i}`,
address: `address${i}`,
}
})
}
return result
}
},
}
</script>
<template>
  <div id="app">
    <button @click="loadDatas">loadDatas</button>
    <h1>datas length:{{ datas.length }}</h1>
  </div>
</template>
<script>
export default {
  name: 'App',
  data() {
    return {
      datas: []
    }
  },
  methods: {
    loadDatas() {
      this.datas = this.getDatas()
    },
    getDatas() {
      const result = []
      for (let i = 0; i < 1000000; i++) {
        result.push({
          id: i,
          info: {
            avatar: `avatar${i}`,
            name: `name${i}`,
            age: `age${i}`,
            job: `job${i}`,
            address: `address${i}`,
          }
        })
      }
      return result
    }
  },
}
</script>
<template> <div id="app"> <button @click="loadDatas">loadDatas</button> <h1>datas length:{{ datas.length }}</h1> </div> </template> <script> export default { name: 'App', data() { return { datas: [] } }, methods: { loadDatas() { this.datas = this.getDatas() }, getDatas() { const result = [] for (let i = 0; i < 1000000; i++) { result.push({ id: i, info: { avatar: `avatar${i}`, name: `name${i}`, age: `age${i}`, job: `job${i}`, address: `address${i}`, } }) } return result } }, } </script>

这段代码看起来很简单,但是它的效率却很低,为什么呢?

我们使用浏览器的性能工具记录一下,看看这段时间内它的主要性能消耗都到哪里去了。

你会发现整个时间里渲染的时间为 0,因为页面很简单,没有什么可渲染的。

而 JS 的加载就耗时 14852 毫秒,那是不是说主要损耗就在这 100 万次的循环呢?

现在马上去验证一下。

打开调用树找到函数,你会发现 loadDatas 函数耗时占用了 66.7%。

那么这个函数里边哪个地方执行时间最长呢?

我们发现根本不是 getDatas 函数,它循环了 100 万次,但是耗时只有 12.4%,所以说效率主要损耗不在这。

而是在 proxySetter 里,我们展开看看里边是什么。

学过 Vue 的同学一定都知道这个 observe 是什么。

Vue 就是靠它来完成数据的响应式的,它遍历数组,遍历数组里的每一个对象,遍历每一个属性,而且是深度遍历,把每一个属性使用 Object.defineProperty 来进行响应式处理,所以说时间主要损耗在这里了。

而我们有些数据压根不需要响应式,最常见的就是列表,或者一些表格数据基本是不需要响应式的。

数据响应式是用来监听数据数据变化的,那我们有没有办法告诉 Vue,我们给它的东西是不需要响应式的呢?

答案是有点的,就是使用冻结对象(Object.freeze)。

loadDatas() {
this.datas = Object.freeze(this.getDatas())
}
loadDatas() {
  this.datas = Object.freeze(this.getDatas())
}
loadDatas() { this.datas = Object.freeze(this.getDatas()) }

只需要将对象冻结,Vue 在处理数据时就会判断这个对象是否是冻结对象,判断的方式是使用 Object.isFrozen 这是 Vue 的内部实现,我们不用管。

当 Vue 发现你给它的数据是一个冻结对象的话,它就不会把对象变成响应式的。

我们再来看一下它的效率。

可以很明显的看到,性能有大幅度的提升。

我们将 this.datas 打印到控制台。

就会发现这些数据就是普普通通的对象,如果说它是一个响应式对象,数据应该是下图这样。

总结

随着效率提升的同时,对象也失去了响应式,你再去改动数据页面也不会收到通知。

所以说优化不能一概而论,学了优化之后把所有的优化手段全用上,要么代码不能看了,要么出的问题比解决的效率问题更大。

一定是因地制宜,具体情况具体分析的。

那么这就需要你懂得很多很多的优化手段,手上得有技术,不然你需要的时候就拿不出来了。

本文来源

本文来源自渡一官方公众号:Duing,欢迎关注,获取最新最全最深入的技术讲解

感谢你阅读本文,如果你有任何疑问或建议,请在评论区留言,如果你觉得这篇文章有用,请点赞收藏或分享给你的朋友!

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MY3kLKrr' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片