Object Pool Pattern in JavaScript

Now that we understand the Recycler Object for Object Pool Pattern, we can build the logic for managing the object pool. An object pool is a simple API that manages recycling and fetching recyclable objects. There are two common models for object pools, one with a fixed number of objects that errors if too many objects are requested, and the other (more flexible approach) is to use the object pool for a fixed number of objects, but allow additional recyclable objects beyond that limit which won’t be recycled (never use an unbounded pool).

Both approaches solve a slightly different problem. For example, a table that always contains exactly 50 rows of replaceable data might use the more rigid object pool, while a framework returning recyclable event wrapper objects would need to be more flexible (20 events firing at once seems like a reasonable limit, but wouldn’t want to error if there were more).

We’ll implement the second approach, but discuss how it might be modified for the first approach.

Getting ready

Read the article, Recycler Object for Object Pool Pattern to understand the qualities of a recyclable object (initialization and recycle functions).

How do it…

Create an object pool handler:

function ObjectPool(iLimit, fnConstructor) {
    this._aObjects = new Array(iLimit);
    this._fnConstructor = fnConstructor;
    this._iLimit = iLimit;
    this._iSize = 0;

    this.obtain = function() {
        var oTemp;
        if (this._iSize > 0) {
            this._iSize--;
            oTemp = this._aObjects[this._iSize];
            this._aObjects[this._iSize] = null;
            return oTemp;
        }

        return fnConstructor();
    };

    this.recycle = function(oRecyclable) {
        if (!oRecyclable instanceof this._fnConstructor) {
            throw new Error("Trying to recycle the wrong object for pool.");
        }

        if (this._iSize < this._iLimit) {
            oRecyclable.recycle();
            this._aObjects[this._iSize] = oRecyclable;
            this._iSize++;
        } else {
            // The pool is full, object will be deferred to GC for cleanup.
        }
    };

    this.getSize = function() {
        return this._iSize;
    };
}

Here is how to create a Point (from previous article) object pool, instantiate the Point from the pool, and then recycle it:

var oPointPool = new ObjectPool(10, Point);
var oPoint1 = oPointPool.obtain();
var oPoint2 = oPointPool.obtain();
// do something with points
oPointPool.recycle(oPoint1);
oPointPool.recycle(oPoint2);

With the object pool pattern, it is important not to recycle the same object twice. When double recycling is suspected, adding a recycled boolean to the recyclable object and adding a check to the recycle function of the pool can be helpful:

function Point() {
    this._bRecycled = true;
    // ...

    this.init = function() {
        this._bRecycled = false;
        // ...
    };

    this.recycle = function() {
        this._bRecycled = true;
        // ...
    };
}

//...
    this.recycle = function(oRecyclable) {
        if (!oRecyclable instanceof this._fnConstructor) {
            throw new Error("Trying to recycle the wrong object for pool.");
        }

        if (oRecyclable._bRecycled) {
            throw new Error("The recyclable object was already recycled.");
        }

        // The same can be done without adding the _bRecycled boolean, but
        // this is non-performance and should not be used in production.
        for (var i = this._iSize; 0 <= i; i--) {
            if (oRecyclable === this._aObjects[this._iSize]) {
                throw new Error("The recyclable object was already recycled.");
            }
        }

        if (this._iSize < this._iLimit) {
            oRecyclable.recycle();
            this._aObjects[this._iSize] = oRecyclable;
            this._iSize++;
        } else {
            // The pool is full, object will be deferred to GC for cleanup.
        }
    };
//...

Lastly, when debugging, you may want to track the high water point of the recycle pool, to better assess what a reasonable limit is (start high, use the application for a while, then adjust down to the high water value):

function ObjectPool(iLimit, fnConstructor) {
    this._iHighWater = 0;
    //...
    this.recycle = function(oRecyclable) {
        if (!oRecyclable instanceof this._fnConstructor) {
            throw new Error("Trying to recycle the wrong object for pool.");
        }

        if (this._iSize < this._iLimit) {
            oRecyclable.recycle();
            this._aObjects[this._iSize] = oRecyclable;
            this._iSize++;

            if (this._iSize > this._iHighWater) {
                this._iHighWater = this._iSize;
            }
        } else {
            // The pool is full, object will be deferred to GC for cleanup.
        }
    };
}

How it works…

The recycle pool is a simple API for obtaining and recycling recyclable object instances. Underneath the hood it manages a pool of recycled object from which it first attempts to fetch an object instance, before instantiating new objects. As objects are recycled they are added to the pool until a maximum is reached; we let the GC handle any overflow objects. This pattern helps normalize the memory thrash of a process. Usually the limit used to instantiate the pool won’t be exceeded, so we have a good idea of the maximum memory expectation. But more importantly we don’t continually create and delete objects from the memory space. Instead we step up to the limit as more objects are added to the pool and stay there.

The biggest gotcha with this pattern is accidentally recycling an object more than once. Doing so can lead to bizarre results if the object is simultaneously modified. A production system can prevent this by monitoring the recycled state of the recyclable object, or a debug system can iterate through the objects in the pool and check for equality.

In this JavaScript implementation the recycle function uses an instanceof of check to make sure the correct recyclable object is being recycled. A statically typed language would prevent the need for this instance of by throwing a compile-time error. In JAVA, for example the ObjectPool class could be instantiated using Generics and that generic class would be required to be passed into the recycle method.

When implementing in another language, you may also need to consider threading issues. If multiple threads will be pulling from the object pool at the same time, then make sure you synchronize (or language equivalent) the obtain and recycle functions.

To build a fixed length object pool, just modify the obtain function to keep track of the number of objects it has instantiated and raise an exception if the number exceeds the limit. Then decide if it makes sense to pay the cost of instantiating the entire pool up front, or when they are first needed.

There’s more…

Read Static Memory Javascript with Object Pools for more information on JavaScript memory churn and using static objects for your JavaScript application.

JavaScript Low Resolution Image Replacer

This is a handy, yet very simple, widget I was hacking on to replace loading or low resolution images with higher resolution ones once the document has finished loading.

How do it…

The widget is built using the jQuery plugin system and here is the complete code:
 (function($) { var isLoaded = false, REPLACEMENT_CLASS = "replacement-class", REPLACEMENT_RCLASS = "replacement-rclass", REPLACEMENT_URL = "replacement-img", TIMER = 500; $(window).load(function() { isLoaded = true; }); function ...

Network Information API Polyfill

One of the many new HTML5 APIs slowly being implemented by browsers is the Network Information API[2]. It exposes information about the type of network that the connecting device is using. In theory, this allows developers to optimize content around the connection speed of the user. However, as with most HTML5 APIs it is supported only by some browsers with/without prefixes, and has a legacy implementation, so a polyfill is useful when working with ...

Detecting Object Mutations by Counting Properties

Have you ever included a library and wonder, "how much did this library add to the window object", or passed an object into a function and asked yourself, "did that function modify my object"? Instead of reading the source code, this article shows a quick trick for answering these questions.

How do it…

For starters we need a function to count the number of properties on an object:
 function fnCountProperties(o) { var ...

Using Google Play Games on the Web

As many of you know, I now work for Google on the Play Games Team. We provide APIs for game developers, implementing useful features like leaderboards and achievements, so the developer doesn't have to. While many Android developers are using our services, adoption on the web could be better, so lets take a look at how to integrate the Google Play Games Services achievements into a web game.

Getting ready

Become a Google developer ...

Event Bubble & Capture Phases

One of the less understood, but powerful feature of browser events are their phases. According to the W3C level 2 spec there are three phases[1]: AT_TARGET=2, BUBBLING_PHASE=3, and CAPTURING_PHASE=1. Most browsers also implement a fourth phase[2]: NONE=0.

Getting ready

Just a quick note that everything discussed in this article is for modern browsers (all browsers except IE <9). Prior to IE 9, Internet Explorer used its own event system, instead of conforming ...

Passing Objects into addEventListener Instead of Functions

I was reviewing the browser event stack the other day and was reminded of a rarely used feature of addEventListener that allows developers to autobind the execution context object, instead of requiring a call to bind or using a library, that is worth sharing, if you weren’t already aware.

How do it…

Typically, when attaching an event, we write:
 var myObj = { handleEvent: function (evt) { // 'this' will be scoped ...

Using Promises to Cache Static AJAX JSON Data

This article showcases a useful caching strategy for static data that is fetch via AJAX. We will use jQuery to setup a promise and cache the data in the localStorage for subsequent page loads or data loads.

Getting ready

A modern web browser supporting localStorage and JSON. Also, a basic understanding of promises[2] is helpful.

How do it…

Here is the code:
 (function($) { var oKeyDeferredMap = {}; function fnReadData(sKey) ...

jQuery Function for Change Event and Delayed Keydown Event

In my experience, it is rare to assign only a change event to a text input, as any callback that would be executed for the change event should also be called on a key event as well, but with a slight delay (think how an autocomplete shows results as you type). This is a common pattern and I was surprised to not immediately find a jQuery plugin implementing it, so I decided to add one ...

Hoisting 102 - Examining a Global Context Hoisting Gotcha

In an earlier article we covered Variable Hoisting in JavaScript. At the time, I did not expect to face a hoisting related code bug so quickly. And given the circumstances of the bug, I expect it to be one of the most common hoisting problems, so I wanted to share it.

How do it…

Let’s jump right into the setup. You have a function that is defined in one JavaScript file (this file ...