Refactoring JavaScript from Sync to Async in Safe Baby-Steps
Consider some JavaScript code that gets and uses a value from a synchronous call or built in data structure:
function to_be_refactored() {
var x;
...
x = get_x();
...use x...
}
Suppose we want to replace this synchronous call with a call to a service that has an asynchronous API (an HTTP fetch, for example).
How can we refactor the code from synchronous to asynchronous style in small safe steps?
First, wrap the the remainder of the function after the line that gets the value in a “continuation” function that takes the value as a parameter and closes over any other variables in its environment. Pass the value to the continuation function:
function to_be_refactored() {
var x, cont;
...
x = get_x();
cont = function(x) {
...use x...
};
cont(x);
}
Then pull the definition of the continuation function before the code that gets the value:
function to_be_refactored() {
var x, cont;
cont = function(x) {
...use x...
};
...
x = get_x();
cont(x);
}
Now extract the last two lines that get the value and call the continuation into a single function that takes the continuation as a parameter and pass the continuation to it.
function to_be_refactored() {
...
get_x_and(function(x) {
...use x...
});
}
function get_x_and(cont) {
cont(get_x());
}
If you have calls to get_x
in many places in your code base, move get_x_and
into a common module so that it can be called everywhere that get_x
is called.
Transform the remaining uses of get_x
to “continuation passing style”, replacing the calls to get_x
with calls toget_x_and
.
Finally, replace the implementation of get_x_and
with a call to the async service and delete the get_x
function.
Wouldn’t it be nice if IDEs could do this refactoring automatically?