Continuation-Passing Style in Javascript
This page is a mirrored copy of an article originally posted on the (now sadly defunct) LShift blog; see the archive index here.
Tue, 11 October 2005
As part of my recent experiments with Javascript, I happened to want a sleep
function. Interestingly, there isn’t one available in browser-side Javascript environments - instead, there are four functions
setInterval
clearInterval
setTimeout
clearTimeout
and they take functions to call after a certain number of milliseconds have gone by. This leads to programming in continuation-passing style (see here, here, here, here, and here):
// ... some code ...
// At this point, we want to pause for one second before continuing.
setTimeout(function () {
// ... code here continues running after 1000 milliseconds have gone by.
}, 1000);
It seems that a (laudable!) design decision has been made for avoiding blocking operations in browser scripting languages. It’s not just sleep
-a-likes, either: the decision affects the design of XmlHttpRequest
, which is used in AJAX-like server callbacks. The way you receive the server’s response to an XmlHttpRequest
message is by supplying a callback function. This again leads to a continuation-passing style of programming - see the definition of AJAJ.proxy
in this file. Here’s an example of AJAJ.proxy
in action, as part of a simple AJAX+JSON chat application:
function rpc(action, arg, k, kfail) {
var urlPrefix = (new RegExp("(.*/)([^/]+)”)).exec(document.location)[1];
AJAJ.proxy(urlPrefix + “chat-server/simple-chat.asp”)
({action: action, arg: arg}, k, kfail);
}
function consoleRpc(action, arg) {
rpc(action, arg,
function (r) { console.recordOutput(formatConsoleRpc(action, arg),
JSON.stringify(r)); },
function (e) { console.recordError(formatConsoleRpc(action, arg),
JSON.stringify(e)); });
}
The two functions k
and kfail
passed to the rpc
function serve as the success and failure continuations, respectively. If the XmlHttpRequest
succeeds, then the function starting with “function (r) { ...
” will be called with the response from the server; otherwise, the function starting with “function (e) { ...
” will be called with an exception object that reports on the failure. We’re using closures to extend the available control structures of the language.