CPS

Continuation Passing Style (CPS)

Continuation Passing Style is common in the node API, among other places. The idea behind continuation passing style is:

  • no function is allowed to return to it's caller.

  • Each function takes a callback or continuation function as its last argument

  • that continuation function is the last thing to be called

continuation is a function, that represents the next step in processing. This continuation is executed in tail position by the current phase of processing once it has finished - the callback is now a continuation to more processing.

function foo() {
  bar(function(res) {
    console.log("result = " + res);
  });
}
function bar(fn) {
  baz(fn);
}
function baz(fn) {
  fn(3);
}
foo();

The above code sample shows a set of functions written using CPS. Each function's last (and only in this example) argument is a callback. Once you start writing functions using CPS, everything else must follow suit and become CPS as well.

Here's the control flow sequence for the above example:

CPS works well for systems that are asynchronous by default, like node, where the event loop constantly runs and the API functions as callbacks. Converting direct style programming to CPS, however, requires some work and some different thinking about how your processing takes place.

// Synchronouse version
const a = 1;
const b = 2;
const c = 3;
const d = 4;
const e = 5;
const r = a + (Math.pow(b, 2) * c) / d - e; // -4

// CPS version
function mul(x, y, cont) {
  cont(x * y);
}
function add(x, y, cont) {
  cont(x + y);
}
function sub(x, y, cont) {
  cont(x - y);
}
function div(x, y, cont) {
  cont(x / y);
}
function sqr(x, cont) {
  cont(x ^ 2);
}

sqr(b, function(res) {
  mul(res, c, function(res) {
    div(res, d, function(res) {
      add(a, res, function(res) {
        sub(res, e, function(res) {
          console.log(res); // -4
        });
      });
    });
  });
});

In order to handle processing, we have to nest each call to retain the scope and results passed to each callback. This gives us another case of the pyramid of doom or callback hell.

Last updated