前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Thinking--JavaScript延迟加载属性数据(性能提升)

Thinking--JavaScript延迟加载属性数据(性能提升)

作者头像
奋飛
发布2021-08-31 17:01:49
6730
发布2021-08-31 17:01:49
举报
文章被收录于专栏:Super 前端

Thinking系列,旨在利用10分钟的时间传达一种可落地的编程思想。

Vue 遍历对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。getter/setter 对用户来说是不可见的,但是在内部 Vue 能够追踪依赖,在 property 被访问和修改时通知变更,依此做到了数据的响应式。

vue 通过 Object.defineProperty 的实现思路,值得我们思考。下面提到的属性延迟加载就是其中一个引发点。

常规写法示例

代码语言:javascript
复制
async function getData() {
  let data = await fetch(new Request('./data.json')).then(res => res.json())
  return data
}
let res = { data: [] }
res.data = await getData()
// res.data 用于页面渲染
render(res.data)

上述写法,在 javascript 编码中可能出现比较少,但在 vue 等开发中,却会经常看到类似的写法:

代码语言:javascript
复制
<script>
	data () {
    return {
      res: {data: []}
    }
  },
  methods: {
    async function getData() {
    	 this.res.data = await fetch(new Request('./data.json')).then(res => res.json())
		}
  },
  created () {
    this.getData()
  }
script>
  • 如果 res.data 在页面渲染时,直接首屏呈现,上述写法没有问题;
  • 如果 res.data 是通过某些操作触发才呈现,那上述写法需要优化。

关于第2种假设,优化点在于**「延迟加载」**。你有可能会说,可以监听触发动作(如click,scroll),然后在相应事件中触发。

代码语言:javascript
复制
document.querySelector('#btn').addEventListener('click', async () => render(await getData()))

上述处理没有问题,但这里想要提到的是属性自动触发的方式 – 借助 Object.defineProperty

延迟加载对象属性

代码语言:javascript
复制
let res = {
  get data() {
    return fetch(new Request('./data.json')).then(res => res.json())
  }
}

// 注意上述是异步
await res.data

这样可以做到在调用 res.data 时,才会执行相关获取数据操作。

缓存结果,避免重复执行

延迟加载(将计算推迟到第一次读取属性时),然后缓存结果以供后续使用。避免重复执行相同的工作是提高性能的最佳方式之一,直接利用缓存结果可以加快运行速度。

代码语言:javascript
复制
let res = {
  get data() {
    let _data = fetch(new Request('./data.json')).then(res => res.json())
    Object.defineProperty(this, 'data', {
      value: _data,
      writable: false,
      configurable: false,
      enumerable: false
    })
    return _data
  }
}

console.log(object.hasOwnProperty("data"))  // true
const data = await object.data
console.log(object.hasOwnProperty("data"))	// true

vue commputed

「延迟加载、缓存结果」这个和 vue computed 实现的效果一样!计算属性是通过 getter 函数延迟加载,基于它们的响应式依赖进行缓存的

Vue 中对于 computed 实现也是借助 defineProperty - https://github1s.com/vuejs/vue/blob/2.6/dist/vue.js#L3580-L3581

代码语言:javascript
复制
function defineComputed (
  target,
   key,
   userDef
) {
  var shouldCache = !isServerRendering();
  if (typeof userDef === 'function') {
    sharedPropertyDefinition.get = shouldCache
      ? createComputedGetter(key)
    : createGetterInvoker(userDef);
    sharedPropertyDefinition.set = noop;
  }
  if (sharedPropertyDefinition.set === noop) {
    sharedPropertyDefinition.set = function () {
      warn(
        ("Computed property \"" + key + "\" was assigned to but it has no setter."),
        this
      );
    };
  }
  Object.defineProperty(target, key, sharedPropertyDefinition);
}

class

class 可以同样实现延迟加载,并对结果做相应的缓存处理。

代码语言:javascript
复制
class MyClass {
  constructor() {
    Object.defineProperty(this, "data", {
      get() {
        // 开销大的操作(如数据请求)
        const actualData = someExpensiveComputation()
        Object.defineProperty(this, "data", {
          value: actualData,
          writable: false,
          configurable: false
        })
        return actualData
      },
      // ①
      configurable: true,
      enumerable: true
    })
  }
}

这里①将 data 设置成可配置尤为重要,因为我们需要对 data 再次调用 Object.defineProperty()

代码语言:javascript
复制
const obj = new MyClass();
console.log(obj.hasOwnProperty("data"))     // true

const data = obj.data;
console.log(obj.hasOwnProperty("data"))     // true
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/08/16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 延迟加载对象属性
  • 缓存结果,避免重复执行
  • vue commputed
  • class
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档