使用对象池创建数据

1,994 阅读1分钟

在React中,使用到pool的地方并不少,比如SyntheticEvent.js中使用事件对象池,来创建销毁事件。ReactChild.js使用child对象池,React.Children.forEach来遍历子节点。

使用对象池来创建数据,可以很好地帮助我们创建那些需要频繁创建销毁的元素,并在性能上做一部分优化。

举例

我们使用Marker来标记地图上的点

参考React.16.6.0SyntheticEvent.js创建事件池的写法

定义Marker对象

function Marker(x, y, containerInfo) {
  this.x = x
  this.y = y
  this.containerInfo = containerInfo
}

Marker.prototype.destroy = function () {
  this.x = null
  this.y = null
  this.containerInfo = null
}

Marker.prototype.show = function () {
  console.log(`x: ${this.x} y:${this.y} containerInfo:${this.containerInfo}`)
}

定义对象池相关

// 对象池大小
const MARKER_POOL_SIZE = 10

// 从pool中得到一个marker对象
function getPooledMarker(x, y, containerInfo) {
  const MarkerConstructor = this
  if (MarkerConstructor.markerPool.length) {
    const instance = MarkerConstructor.markerPool.pop()
    MarkerConstructor.call(instance, x, y, containerInfo)
    return instance
  }
  return new MarkerConstructor(x, y, containerInfo)
}

// 归还一个marker对象到pool中
function releasePooledMarker(marker) {
  const MarkerConstructor = this
  if (marker instanceof MarkerConstructor === false) {
    throw Error() // 当前marker不是由其创造,错误提示
  }
  marker.destroy()
  if (MarkerConstructor.markerPool.length < MARKER_POOL_SIZE) {
    MarkerConstructor.markerPool.push(marker)
  }
}

// 向Marker上挂载对象池的方法
function addMarkerPoolingTo(MarkerConstructor) {
  MarkerConstructor.markerPool = []
  MarkerConstructor.getPooled = getPooledMarker
  MarkerConstructor.release = releasePooledMarker
}

// 将对象池应用到Marker上
addMarkerPoolingTo(Marker)

使用方式

这里手动释放marker,即marker = null

// 未使用对象池
let marker1 = new Marker(1, 1, 'container1')

marker1.show()

marker1.destroy()
marker1 = null


// 使用对象池
let marker2 = Marker.getPooled(2, 2, 'container2')

marker2.show()

Marker.release(marker2)
marker2 = null