Refactoring Asynchrony in JavaScript
This work is currently under submission
JavaScript is a widely used programming language that makes extensive use of asynchronous computation, particularly in the form of asynchronous callbacks. These callbacks are used in modern JavaScript applications to handle tasks, from GUI events to network messages, in a non-blocking fashion. Asynchronous callbacks present developers with two challenges. First, JavaScript’s try/catch error-handling mechanism is not sufficient for proper error handling in asynchronous contexts. In response, the JavaScript community has come to rely on the error-first protocol, an informal programming idiom that is not enforced or checked by the JavaScript runtime. Second, JavaScript callbacks are frequently nested, making them difficult to handle (also known as callback hell). Fortunately, a recent language extension called promises provides an alternative to asynchronous callbacks. The adoption of promises, however, has been slow as refactoring existing code to use promises is a complex task.
In this paper we present a set of program analysis techniques to detect instances of asynchronous callbacks and to refactor such callbacks, including callbacks with the error-first protocol, into promises. We implement our techniques in a tool called PromisesLand. We perform a manual analysis of four JavaScript applications to evaluate the tool’s precision and recall, which are, on average, 100% and 83%, respectively. We evaluate PromisesLand on 21 large JavaScript applications, and find that PromisesLand (1) correctly refactors callbacks to promises, (2) outperforms a recent related refactoring technique, and (3) runs in under three seconds on all of our evaluation targets.
Full dataset can be downloaded from here:
Source code used to analyze the subject systems can be accessed here:
Reasons motivating developers to use Promises over callbacks:
This set of subject systems consist of 21 Node.js modules and is expected to be representative of a majority of commonly used JavaScript modules.