Sequencing futures in JavaScript

May 22, 2015

Earlier, we looked at an approach to building futures in JavaScript. This gave us apply, map, and flatMap, but left us without a way to collect the results of multiple concurrent futures. Let's build a way to do it.

As before, consider a simple AJAX call:

function getConstants(k) {
  var xhr = new XMLHttpRequest();
  xhr.onload = function () {
    var constants = JSON.parse(this.responseText);
    k(constants);
  };
  xhr.open('get', 'futures-sequence/constants.json', true);
  xhr.send();
}

The file futures-sequence/constants.json contains some constants:

{
  "pi": 3.14,
  "e": 2.72
}

Let's make two independent futures out of getConstants:

var getPi = future(getConstants).map(function (constants) { return constants.pi; });
var getE  = future(getConstants).map(function (constants) { return constants.e; });

Instead of dealing with two independent futures (that each return a single constant), let's combine them into a single future that returns both constants.

var future = function (f) {
  return {
    apply: // ...
    map: // ...
    flatMap: // ...
    sequence: function (f2) {
      var xs = [];
      return future(function (k) {
        var kk = function() {
          if (xs.length === 2) {
            k(xs);
          }
        };
        f(function (x) {
          xs.unshift(x);
          kk();
        });
        f2.apply(function (x) {
          xs.push(x);
          kk();
        });
      });
    }
  };
};

If JavaScript had type annotations, sequence would look something like this:

sequence : <B>(f: Future<B>) => Future<[A,B]>;

Now we can sequence getPi and getE into a single future that takes a callback expecting both Pi and e:

var showPiAndE = function (xs) {
  return 'Pi: ' + xs[0] + ', e: ' + xs[1];
}

var futureShowPiAndE = getPi.sequence(getE).map(showPiAndE);

Demo

This implementation of future is available in futures-sequence/future.js, and the above examples are available in futures-sequence/demo.js.

Callback: alert

Try this link, and watch the alert:

Callback: println

Try this link, and watch the JavaScript console: