博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
解读 React 的 pooledClass.js
阅读量:5733 次
发布时间:2019-06-18

本文共 3958 字,大约阅读时间需要 13 分钟。

前言

在学习 React 的时候,在事件分发的 dispatch方法发现了调用了一个 pooledClass 方法,一时半会没看明白这个方法的用意。

我们先看一下是怎么用的:

// step1function TopLevelCallbackBookKeeping(topLevelType, nativeEvent) {  this.topLevelType = topLevelType;  this.nativeEvent = nativeEvent;  this.ancestors = [];}Object.assign(TopLevelCallbackBookKeeping.prototype, {  destructor: function() {    this.topLevelType = null;    this.nativeEvent = null;    this.ancestors.length = 0;  },});PooledClass.addPoolingTo(  TopLevelCallbackBookKeeping,  PooledClass.twoArgumentPooler);// step2var bookKeeping = TopLevelCallbackBookKeeping.getPooled(  topLevelType,  nativeEvent);// bookKeeping 是 TopLevelCallbackBookKeeping 的实例try {  // Event queue being processed in the same cycle allows  // `preventDefault`.  ReactUpdates.batchedUpdates(handleTopLevelImpl, bookKeeping);} finally {  //释放  TopLevelCallbackBookKeeping.release(bookKeeping);}

那么这里为什么不直接 new 一个 TopLevelCallbackBookKeeping, 而要通过这个 PooledClass 来返回 TopLevelCallbackBookKeeping 的实例呢

对象池

单例模式是限制了一个类只能有一个实例,对象池模式则是限制一个类实例的个数。对象池类就像是一个对象管理员,它以Static列表(也就是装对象的池子)的形式存存储某个实例数受限的类的实例,每一个实例还要加一个标记,标记该实例是否被占用。当类初始化的时候,这个对象池就被初始化了,实例就被创建出来。然后,用户可以向这个类索取实例,如果池中所有的实例都已经被占用了,那么抛出异常。用户用完以后,还要把实例“还”回来,即释放占用。对象池类的成员应该都是静态的。用户也不应该能访问池子里装着的对象的构造函数,以防用户绕开对象池创建实例。书上说这个模式会用在数据库连接的管理上。比如,每个用户的连接数是有限的,这样每个连接就是一个池子里的一个对象,“连接池”类就可以控制连接数了。
如果说每次触发
dispatch 的时候都用 new TopLevelCallbackBookKeeping 来 new 一个对象,那么当触发很多次
dispatch 的时候,就会导致生成多个对象无法销毁(多个bookKeeping的引用次数一直为1),导致内存溢出。

对象池技术的基本原理

对象池技术基本原理的核心有两点:缓存和共享,即对于那些被频繁使用的对象,在使用完后,不立即将它们释放,而是将它们缓存起来,以供后续的应用程序重复使用,从而减少创建对象和释放对象的次数,进而改善应用程序的性能。事实上,由于对象池技术将对象限制在一定的数量,也有效地减少了应用程序内存上的开销。

对象池使用的基本思路是

将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用,从而在一定程度上减少频繁创建对象所造成的开销。React 的 pooledClass.js 就是一个例子:

var invariant = require('invariant');/** * Static poolers. Several custom versions for each potential number of * arguments. A completely generic pooler is easy to implement, but would * require accessing the `arguments` object. In each of these, `this` refers to * the Class itself, not an instance. If any others are needed, simply add them * here, or in their own files. */var oneArgumentPooler = function(copyFieldsFrom) {  var Klass = this;  if (Klass.instancePool.length) {    var instance = Klass.instancePool.pop();    Klass.call(instance, copyFieldsFrom);    return instance;  } else {    return new Klass(copyFieldsFrom);  }};...var standardReleaser = function(instance) {  var Klass = this;  invariant(    instance instanceof Klass,    'Trying to release an instance into a pool of a different type.'  );  instance.destructor();  if (Klass.instancePool.length < Klass.poolSize) {    Klass.instancePool.push(instance);  }};var DEFAULT_POOL_SIZE = 10;var DEFAULT_POOLER = oneArgumentPooler;/** * Augments `CopyConstructor` to be a poolable class, augmenting only the class * itself (statically) not adding any prototypical fields. Any CopyConstructor * you give this may have a `poolSize` property, and will look for a * prototypical `destructor` on instances (optional). * * @param {Function} CopyConstructor Constructor that can be used to reset. * @param {Function} pooler Customizable pooler. */var addPoolingTo = function(CopyConstructor, pooler) {  var NewKlass = CopyConstructor;  NewKlass.instancePool = [];  NewKlass.getPooled = pooler || DEFAULT_POOLER;  if (!NewKlass.poolSize) {    NewKlass.poolSize = DEFAULT_POOL_SIZE;  }  NewKlass.release = standardReleaser;  return NewKlass;};var PooledClass = {  addPoolingTo: addPoolingTo,  oneArgumentPooler: oneArgumentPooler,  twoArgumentPooler: twoArgumentPooler,  threeArgumentPooler: threeArgumentPooler,  fourArgumentPooler: fourArgumentPooler,  fiveArgumentPooler: fiveArgumentPooler,};module.exports = PooledClass;

具体分为三步

  1. addPoolingTo 添加对象到池子
  2. 调用的时候发现是否有缓存,有缓存就pop()出来用, 没有缓存就新增一个
  3. 使用完成之后,释放对象,缓存进去

说的再简单一点就是

  • 创建对象 addPoolingTo()
  • 借取对象 getPooled()
  • 归还对象 release()

总结

并非所有对象都适合拿来池化――因为维护对象池也要造成一定开销。对生成时开销不大的对象进行池化,反而可能会出现“维护对象池的开销”大于“生成新对象的开销”,从而使性能降低的情况。但是对于生成时开销可观的对象,池化技术就是提高性能的有效策略了。

转载地址:http://iumwx.baihongyu.com/

你可能感兴趣的文章
关于byte[]字节传输的大端和小端小议
查看>>
【百度地图API】多家地图API内存消耗对比测验(带源码)
查看>>
android 画图之setXfermode .
查看>>
【DeepLearning】Exercise:Softmax Regression
查看>>
请求(Request)的参数(Parameter)里包含特殊字符(#等)的正确处理方式
查看>>
POJ2992:Divisors(求N!因子的个数,乘性函数,分解n!的质因子(算是找规律))...
查看>>
Linux学习之十四、管线命令
查看>>
C++里面的取整函数
查看>>
ssis 到别的表查找临时变量值
查看>>
让下拉框中同时显示Key与Value
查看>>
C#反射Assembly 具体说明
查看>>
[控件] 创建出条形间隔效果的背景LineBackgroundView
查看>>
objective-c 语法快速过(8)
查看>>
搭建Git本地服务器
查看>>
:nth-child() 选择器
查看>>
Ubuntu下deb包的安装方法
查看>>
DeviceIoControl的使用说明
查看>>
面试题20:顺时针打印矩阵递归和非递归两种方式实现
查看>>
Spring(五)AOP简述
查看>>
maven pom.xml 配置详解
查看>>