前言
JavaScript中,通常我们通过以下方式创建变量:
1 | let v = 1; |
数据变量分为两大类型,基本类型以及引用类型,基本类型包括String,Boolean,Symbol,Number,null, undefined, BigInt这七大种,而引用类型通常是我们所说的Object,包括数组,对象,函数等。
我们在创建变量,其实就是分配内存的过程,JavaScript自带垃圾回收机制,通过内部的机制回收内存,然而js内部是通过怎样的方式判断可以进行垃圾回收了呢?dangdang~~ 那就是变量的引用。
这里主要介绍垃圾回收算法,垃圾回收算法主要依赖于引用的概念,在内存管理的环境,一个对象如果有访问另一个对象的权限(隐式或显式),叫做一个对象引用另外一个对象。
在这里,“对象”的概念不仅特指普通对象,还包括函数作用域。
对象js的内存管理原理,我就不班门弄斧介绍一遍了,详细请看MDN的介绍,Memory Management
正文
下面分享下以前老东家项目的处理方案,在复杂的业务场景,如何进行内存释放。简单来说,就是如何设计一种比较合理的方式,清除不再使用的变量数据。复杂的业务功能,伴随着复杂的数据类型以及结构,如果不手动进行清除,很可能导致内存占用过多,造成程序崩溃。本方案基于面向对象编程思维,每个业务模块通过定义class,创建instance实例维护数据及方法。
参考了当时源哥的写法,源哥是我当时的大佬,repest!有机会专门写一篇源哥的我的影响,源哥的github
既然是通过面向对象,在实际的项目中,会通过new className这种方式创建不同业务的实例,因此,本方案的做法是定义一个基础类GCBaseService,把内存释放逻辑封装起来,各个模块类型通过extends的方式继承基础类。
说得好像比较模糊,show me code…
1 | export class GCBaseService { |
以上是我们定义好的基本class,如何使用:
1 |
|
调用方式:
1 | let demo = new Demo(); |
当调用了实例当destroy()方法,其实就是触发了onDestroy()的逻辑。这里你可能有疑问,为什么需要通过这种方式,多此一举呢?
其实这里有个拓展的场景,把所有变量清除的工作放在onDestroy()总感觉比较受限,于是,引入RxJS的概念,上面你也发现我注释了部分代码,完整版如下,我们需要再定义一个
回收订阅类GCService。
1 | export default class GCService { |
在constructor里面,我们采用take(1)的方式,保证发布垃圾回收只会触发一次。
回到最初的创建的demo类,如果你的项目刚好也是采用RxJs管理数据流的,可以通过源流定义takeUntil, 传入this.gcService.gc$,就是可以在destory的时候控制停止接受数据,使得这个回收机制的设计更加丰富。
1 | class demo extends GCBaseService { |
总结:
讲道理,本套方案的设计并不复杂,亮点在于形成了一种编码规范,把一些琐碎而又不可忽视的逻辑封装了起来,让团队成员很舒服地用起来,在多人开发中,更容易回溯项目代码,而且这样设计,不是很优雅嘛?溜了溜了
完。