Gary Sieling

Functional Programming Patterns in Four Popular Javascript Libraries

I generally find discussions of design patterns a bit dry, but in testing new Javascript libraries, I’ve stumbled across some interesting tactics. Object oriented design patterns are typical not a perfect fit to Javascript, given it’s untyped nature. The language lends itself more to powerful functional programming techniques. I find studying libraries particularly helpful, as academic tomes often miss context for how one might use various data structures practically.

ExtJS – Config Objects

ExtJS is a Javascript framework for rich desktop-style UIs. The library provides a host of controls: grids, date pickers, charts, etc. When you want to create an object, you call a constructor or provide a type name (the ‘xtype’), which Ext uses to look up registered types.

When you construct an object, you can provide a configuration object, which lets you control the end result. Under the hood Ext creates a blank object, adds functions and values from the type definition, then uses the Javascript “apply” method to combine your data with the base object.

Ext.create('Ext.panel.Panel', {
    title: 'Panel with ButtonGroup',
    width: 300,
    height:200,
    renderTo: document.body,
    bodyPadding: 10,
    html: 'HTML Panel Content',
    tbar: [{
        xtype: 'buttongroup',
        columns: 3,
        title: 'Clipboard',
        items: [{
            text: 'Paste',
            scale: 'large',
            rowspan: 3,
            iconCls: 'add',
            iconAlign: 'top',
            cls: 'btn-as-arrow'
        }]
    }]
});

These configuration objects are deceptively simple, and superficially don’t appear to belong in a discussion of functional programming. Since this pattern lets you simultaneously copy and update any portion of an object, you are fairly close to working with immutable objects (although in practice I’ve not seen anyone treat Ext objects this way).

Config objects aren’t just for specifying defaults – Ext uses them internally to support object hierarchies, static methods, mixins, and multiple inheritance. This also provides trivial copy constructors, “what-if” analysis, and in some cases, code which is naturally self-documenting.

Lunr.js – serialization

Lunr.js is a Javascript library to build full text indexes. It implements an interesting extension to the prior concept – it provides an API to get a serializable object. This is a non-cyclic object clean of functions for serializing/deserializing.

var serializedIndex = JSON.stringify(index1.toJSON())
var deserializedIndex = JSON.parse(serializedIndex)
var index2 = lunr.Index.load(deserializedIndex)

Once created, this object can be used in the same fashion as the Ext config object to create a new full-text index. This makes it easy to feed data from one application to another (from a search index to a map-reduce job, CouchDB entry, or JAX-RS bean in Java)

Pdf.js – Promises

PDF.js is a Firefox Labs project, intending to render a PDF entirely in Javascript + Canvas. The rendering process makes heavy use of a design pattern called Promises.

I’ve seen Promises in Scala, but never gave much thought to how they were implemented. PDF.js isn’t the first or most complete implementation, but is a great demonstration of where they’re useful. This asynchronous pattern seems like a nice fit for rendering – you could make different drawing operations run in parallel, e.g. to render each page of a PDF on a separate thread.

Promises are objects representing future state, allowing you to write code that operates on the results of an unfinished asynchronous call – if you can also tie in error handling to failures. Ideal implementations also allow chaining promises. This is implemented using objects which store callbacks, which are used once the Promise is ready:

var pdf = PDFJS.getDocument('42.pdf');
pdf.then(function(pdf) {
 var maxPages = pdf.pdfInfo.numPages;
 for (var j = 1; j <= maxPages; j++) {
    var page = pdf.getPage(j);

    var processPage = function processPage(pageData) {
      ...
    }

    page.then(processPage);
 }
});

D3 – continuations

D3 is a Javascript visualization library, which makes extensive use of nested closures, to dramatic effect. Structurally the code bears resemblence to Promises, but is much cleaner. It provides the potential for asynchronous coding (for instance, in animations). Unlike Promises, it results in a much smoother mix of synchronous and asynchronous code, without nested callback hell.

Each function call produces a new object, closed around the old object. Because values are a series of closures, they need not be be evaluated until the end. The one downside to this approach is it is a more difficult to reverse engineer than sometime like ExtJS.

This is basically the same as functional lists in Okasaki’s Purely Functional Data Structures.

The objects provide some basic list operations, e.g.:

concat, each, every, filter, forEach, indexOf,
insert, join, map, lastIndexOf, order, pop, push, 
reduce, reduceRight, remove, reverse, shift, 
slice, some, sort, splice

They also provide some DOM manipulation methods:

append, attr, data, node, transition, 
select, selectAll, style, text

These methods also typically accept values or callbacks, a powerful model for behavior customization.

svg = d3.select("body").append("svg");

svg.attr("id", name)
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

...

bar.data(histo)
    .transition()
    .delay(1000)
    .duration(1000);
Exit mobile version