react分析(四)对象池PooledClass

V:\work\react-source\react\lib\PooledClass.js

 /**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */

'use strict';



/**
 * 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 twoArgumentPooler = function (a1, a2) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, a1, a2);
    return instance;
  } else {
    return new Klass(a1, a2);
  }
};

var threeArgumentPooler = function (a1, a2, a3) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, a1, a2, a3);
    return instance;
  } else {
    return new Klass(a1, a2, a3);
  }
};

var fourArgumentPooler = function (a1, a2, a3, a4) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, a1, a2, a3, a4);
    return instance;
  } else {
    return new Klass(a1, a2, a3, a4);
  }
};

var standardReleaser = function (instance) {
  var Klass = this;
  !(instance instanceof Klass) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Trying to release an instance into a pool of a different type.') : _prodInvariant('25') : void 0;
  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.
 *
 * @param {Function} CopyConstructor Constructor that can be used to reset.
 * @param {Function} pooler Customizable pooler.
 */
var addPoolingTo = function (CopyConstructor, pooler) {
  // Casting as any so that flow ignores the actual implementation and trusts
  // it to match the type we declared
  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
};

react对象池使用方法

var a = function foo(){

// 对象池的类需要实现destructor方法,当release时调用该方法,该实现可以在prototype中

  this.destructor = function(){

    console.log('destructor')

  }

  console.log('foo')

};

// 把一个对象(其实就是类构造函数)“添加到”对象池,这步并没有真正到把类添加到对象池中,只是在这个类上添加了一些对象池相关的属性和方法getPooled、instancePool等,instancePool用于保存类的实例。

PooledClass.addPoolingTo(a);

// 真正添加到对象池是在使用这个类的时候,这里的逻辑是如果类instancePool里面包含实例,则通过pop()取出返回,否则new一个

var inst = a.getPooled();

//释放对象的时候,需要把实例传入,然后调用实例的destructor,最后把实例添加a.instancePool队列

a.release(inst);

// 重复上面的逻辑,直接从instancePool中pop()

var b = a.getPooled();

// 由于上面getPooled后没有手动release,所以下面的getPooled会直接new

var b = a.getPooled();

对象池和单例模式比较类似,第一次使用后,释放的时候对象保存起来,这样第二次可以直接使用。

使用对象池的好处:

1、减少每次对象new实例化时的性能消耗,特别针对短时间内频繁创建对象

2、手动释放对象这个释放时间是可把控的,不需要GC机制,自个浏览器实现GC存在异同,这里的释放不是指消耗实例,而是释放当前实例的一些属性,比较this.bigData = null,释放后再把实例添加到对象池队列

坏处:

1、维护对象池也存在性能消耗

2、如果创建对象的过程并不复杂,对象池作用不大

发表评论

电子邮件地址不会被公开。 必填项已用*标注