Skip to content
This repository

If you pass !_ instead of _ when calling a streamline function, the function will execute synchronously and return a future. The future is just a function that you can call later to obtain a result. Let us see how it works on an example:

function countLines(path, _) {
  return fs.readFile(path, "utf8", _).split('\n').length;
}

function compareLineCounts(path1, path2, _) {
  // parallelize the two countLines operations
  var n1 = countLines(path1, !_);
  var n2 = countLines(path2, !_);
  // join the results
  return n1(_) - n2(_);
}

In this example, countLines is called synchronously, with !_. These calls start the fs.readFile asynchronous operations and return two futures (n1 and n2). Later, n1(_) and n2(_) retrieve the results via callbacks that are automatically generated by the streamline transformation engine.

Note: syntax has changed. In 0.8 and before you could just omit the _ parameter or pass null. This syntax was cute but it led to difficult debugging when the _ was left out by mistake. The new syntax makes it possible to verify (at runtime) that the function is called with either _ or !_.

Streamline does not really provide any special API to manipulate futures (and it does not provide any promise abstraction either). The future which is returned is a simple function that takes a single callback parameter. You can evaluate the future from streamline source by calling it with _ but you can also pass the future to a non-streamline module which will evaluate it by calling it with a standard node callback (function(err, result) { ... }).

You can use futures to parallelize operations on an array. For example, the following function will compute the number of lines for an array of file names:

var flows = require("streamline/lib/util/flows");

function lineCounts(paths, _) {
  // start all the operations in parallel
  var futures = paths.map(function(path) {
    return countLines(path1, !_);
  });
  // collect the results into an array
  return flows.collect(_, futures);
}

Of course, this lineCounts function is another streamline function. So you can call it without any callback; it will return a future which resolves into an array of line counts. You can call it either as:

// classical way: pseudo-synchronous
var counts = lineCounts(paths, _);

or as:

// get a future
var countsF = lineCounts(paths, !_);
// do other things while lineCounts is running
doSomethingElse(_);
// get the future's value
var counts = countsF(_);

You can also implement this behavior in regular Javascript APIs (non-streamlined) by adding one line of code at the beginning of every asynchronous function:

var future = require("streamline/lib/util/future").future;

function myAsyncFunc(arg1, arg2, callback) {
  if (callback === false) return future.call(this, myAsyncFunc, arguments, 2);
  // myAsyncFunc body goes here
}

The last parameter of the future function is the index of the callback parameter. If you omit it, future will assume that the callback is the last parameter (so it could be omitted in the example above).

If you are interested by the more academic aspects of this design, you can read this: http://bjouhier.wordpress.com/2011/04/04/currying-the-callback-or-the-essence-of-futures/

Something went wrong with that request. Please try again.