文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

JavaScript中延迟加载属性

2024-12-03 05:43

关注

本文转载自微信公众号「TianTianUp」,作者小弋 。转载本文请联系TianTianUp公众号。

大家好,我是TianTian。

今天分享的内容是JavaScript中延迟加载属性模式。

改善性能的最好方法之一是避免重复两次相同的工作。

因此,只要可以缓存结果供以后使用,就可以加快程序的速度。

诸如延迟加载属性模式之类的技术使任何属性都可以成为缓存层以提高性能。

这里说到的延迟加载属性模式就是利用的访问器属性,将计算昂贵的操作推迟到需要时再使用。

场景

有些时候,你会在JavaScript类内部创建一些属性,它保存实例中可能需要的任何数据。

对于在构造函数内部随时可用的小数据而言,这不是问题。

但是,如果需要在实例中可用之前计算一些大数据,则您可能需要执行昂贵的计算操作。例如,考虑此类:

  1. class MyClass { 
  2.     constructor() { 
  3.         this.data = someExpensiveComputation(); 
  4.     } 

在这里,该data属性是执行一些昂贵的计算而创建的。

如果您不确定将使用该属性,则提前执行可能不太好,效率低。幸运的是,接下来介绍几种方法可以将这些操作推迟。

接下来主要围绕的访问器属性来展开的。

按需属性模式

优化执行计算操作的最简单方法是等到需要数据后再进行计算。

例如,您可以使用带有getter的data属性来按需进行计算,如下所示:

  1. class MyClass { 
  2.     get data() { 
  3.         return someExpensiveComputation(); 
  4.     } 

在这种情况下,直到有人第一次读取该data属性时,您的昂贵的计算操作才发生,这是一种改进。

但是,也是存在问题的,每次data读取属性时都会执行相同的昂贵计算操作,这比之前的示例(其中至少仅执行一次计算)差。

按照我们分析的情况来看,这不是一个好的解决方案,所以可以在此基础上创建一个更好的解决方案。

延迟加载属性模式

只有在访问该属性时才执行计算是一个好的开始。您真正需要的是在那之后缓存信息,然后仅使用该缓存的数据结果。

但是,有个问题需要我们考虑,您将这些信息缓存在何处以便于访问呢?

最简单的方法是定义一个具有相同名称的属性,并将其值设置为计算出的数据,如下所示:

  1. class MyClass { 
  2.     get data() { 
  3.         const actualData = someExpensiveComputation(); 
  4.         Object.defineProperty(this, "data", { 
  5.             value: actualData, 
  6.             writable: false
  7.             configurable: false
  8.             enumerable: false 
  9.         }); 
  10.         return actualData; 
  11.     } 

在这里,该data属性再次被定义为该类的getter,但是这一次它将缓存结果。

调用Object.defineProperty()创建一个名为的新属性data,该属性的固定值为actualData,并且被设置为不可写,不可配置和可枚举。

下次data访问该属性时,它将从新创建的属性中读取而不是调用getter:

  1. const object = new MyClass(); 
  2. // calls the getter 
  3. const data1 = object.data; 
  4. // reads from the data property 
  5. const data2 = object.data; 

实际上,所有计算仅在第一次读取数据属性时完成。数据属性的每次后续读取都将返回缓存的版本。这种模式的缺点是data属性开始时是不可枚举的原型属性,最后是不可枚举的自己的属性:

  1. const object = new MyClass(); 
  2. console.log(object.hasOwnProperty("data"));     // false 
  3. const data = object.data; 
  4. console.log(object.hasOwnProperty("data"));     // true 

尽管这种区别在许多情况下并不重要,但了解这种模式很重要,因为在传递对象时,这种模式可能会引起细微的问题。

幸运的是,我们可以使用接下来的模式很容易解决这个问题。

类的延迟加载属性

如果您有一个实例,对于这个实例,延迟加载属性存在很重要,那么您可以使用Object.defineProperty()在类构造函数内部创建该属性。

它比前面的示例有点混乱,但是它将确保该属性仅存在于实例上。这是一个例子:

  1. class MyClass { 
  2.     constructor() { 
  3.         Object.defineProperty(this, "data", { 
  4.             get() { 
  5.                 const actualData = someExpensiveComputation(); 
  6.                 Object.defineProperty(this, "data", { 
  7.                     value: actualData, 
  8.                     writable: false
  9.                     configurable: false 
  10.                 }); 
  11.                 return actualData; 
  12.             }, 
  13.             configurable: true
  14.             enumerable: true 
  15.         }); 
  16.     } 

我们从这个例子中可以发现,构造函数使用创建data访问器属性Object.defineProperty()。该属性是在实例上创建的(使用this),定义了一个getter并指定了可枚举和可配置的属性。

将data属性设置为可配置尤其重要,这样您可以Object.defineProperty()再次调用它。

然后,getter函数进行计算并再次调用Object.defineProperty()。对于data来说,将该属性重新定义为具有特定值的数据属性,并且将其变为不可写且不可配置以保护最终数据。下次data读取该属性时,将从存储的值中读取该属性。该data属性现在仅作为自己的属性存在,并且在第一次读取之前和之后都具有相同的作用:

  1. const object = new MyClass(); 
  2. console.log(object.hasOwnProperty("data"));     // true 
  3.  
  4. const data = object.data; 
  5. console.log(object.hasOwnProperty("data"));     // true 

对于类,这很可能是您要使用的模式。另一方面,对象模式下可以使用更简单的方法。

对象的延迟加载属性

如果使用的是对象模式而不是类,则过程要简单得多,因为在对象模式上定义的getter与数据属性一样被定义为可枚举的自身属性(而不是原型属性)。这意味着您可以为类使用延迟加载属性模式,而不会造成混乱:

  1. const object = { 
  2.     get data() { 
  3.         const actualData = someExpensiveComputation(); 
  4.  
  5.         Object.defineProperty(this, "data", { 
  6.             value: actualData, 
  7.             writable: false
  8.             configurable: false
  9.             enumerable: false 
  10.         }); 
  11.  
  12.         return actualData; 
  13.     } 
  14. }; 
  15. console.log(object.hasOwnProperty("data"));     // true 
  16. const data = object.data; 
  17. console.log(object.hasOwnProperty("data"));     // true 

总结

 

通过从重新定义为数据属性的访问器属性开始,您可以将计算推迟到第一次读取该属性时,然后将结果缓存起来以备后用。这种方法适用于类和对象文字,并且在对象模式中更简单一些,因为您不必担心getter最终会出现在原型上。

 

来源:TianTianUp内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯