One of the features of promises, in the Promises/A+ sense, is that they capture thrown exceptions so they can be handled asynchronously. This has the negative consequence that it is possible for an error to be silently ignored forever. There is a long list of measures that can mitigate this problem, but the real solution is to use a Promise Inspector.
There is a less obvious class of problems a promise inspector can surface: the forever pending promise. Consider a promise inspector that shows a pending promise until it is either fulfilled or rejected. If a program reaches an obviously idle or stable state and a pending promise remains in the inspector, it is the harbinger of a problem, and the best place to start inspecting.
There is precedent for promise inspectors. The most noteworthy is Causeway, a promise debugger designed for Mark Miller’s E programming language. Ember Extension has recently introduced a promise inspector. There is also a proof-of-concept for a Chrome Extension that introduces a Promise inspector for the Q promise library.
Promises come and go over the life of a program. As such, it is not practical to retain the entire history of promises in the memory of either a promise inspector or a promise library. It is however practical for a library to retain an index of all pending promises and all promises that have been rejected but not yet handled. It would also be practical for a promise inspector to retain a circular buffer of a limited size for all other promises for the purpose of tracing.
The scope and life of a promise inspector panel and inspected windows overlap but are disjoint. Ideally, there would be one promise inspector panel for each window under test and their lives would be coordinated, but this is not the case for multiple reasons. Reloading the inspected window does not cause the inspector window to reload. The inspector window can be opened and closed multiple times during the lifetime of a single inspected window, open or closed when the inspected page loads, or open or closed when the inspected page unloads. Furthermore, an inspected page does not necessarily only contain one instance of a promise library, and an inspector window does not necessarily need to limit itself to watching a particular page.
It is not merely conceivable that a promise inspector could watch promises from multiple windows, processes, or instances of various promise libraries, but Causeway is explicitly designed to show the causal relationships between promises in programs distributed over a network.
This implies some basic requirements for a promise inspector protocol for Chrome Extensions.
- A promise library must be able to communicate with any number of inspectors simultaneously.
- A promise inspector must be able to communicate with any number of promise libraries, across any number of windows, across any number of processes simultaneously. But for now, just one that will come and go at random, and may or may not be already there when the inspector window loads.
- Individual promises must have universally unique identifiers. This might imply a crytorandom identifier, or just a sequential number attached to a cryptorandom promise library instance identifier.
- A promise library must retain a snapshot of all currently pending and rejected but unhandled promises and be able to transmit this snapshot and all subsequent changes each time it connects or reconnects to a promise inspector window.
- A promise inspector must be able to display stack traces corresponding to where a promise was constructed, their state (pending, fulfilled, rejected, thenable, remote), and their resolution if they are initially pending. The inspector is at liberty to use this information for a variety of visualizations.
Also, the message transport mechanism between an inspected window and an inspector window, with the agents coming and going, is roughly as reliable as any shared network. It might become necessary to construct something like TCP/IP over message ports so multiple objects within multiple contexts can reliably communicate over bidirectional streams.