Debugging Web Workers in IE10
In IE10, we’ve enhanced the F12 tools to be aware of the new script contexts created for every Web worker. When you start debugging (by clicking the Start debugging button within the F12 tools), you’re attaching to the Web page’s script context as well as the context of any currently running (or future) worker. This is what we mean by complete and predictable script debugging: all of the script debugging and profiling features that are available in F12 for traditional single-threaded script behave the same for workers.
The alternative is supporting limited debugging via emulation. Currently, many developer tools don’t support Web Worker debugging at all. Others only offer it in a simulated environment, for example, using iframes to emulate workers. Unfortunately, the simulations could mislead developers because the debugger allows invalid scenarios (e.g. DOM access) that would fail during normal execution to succeed while debugging.
A debugger that offers an unfaithful representation of runtime behavior often results in confusing “heisenbugs,” especially when migrating existing code over to use workers. In addition, the simulated environments run in the UI’s thread context, which puts your application at risk of becoming unresponsive while debugging. Both of these potential gotchas make it valuable for developers to have true debugging support for applications that make use of Web Workers.
Building on what you already know
Since F12 provides the same support for Web Workers as it does for regular scripts, you already know most of how to debug them. You can set breakpoints within a worker’s executing script, view any local variables, set watches, interact with the worker via the console, and step through code. This allows developers who are familiar with script debugging to be immediately productive with Web Workers today. There are, however, a few points of interest—with regards to worker debugging—that are worth calling out (all screenshots below are using the Web Worker Harness for test262 demo app).
When your script creates a new Worker object, and the worker’s script context has been initialized, the script file it is executing will be displayed in the list of script resources. From here, you’ll be able to select the file and begin debugging as usual.
Screen shot showing F12 developer tools’ Script tab and available scripts menu
When you’re sitting at a breakpoint within a Web Worker’s script, and you inspect any of its variables or scope, you’ll notice one key difference between it and regular scripts: it will have a global object of type WorkerGlobalScope as opposed to the traditional Window object. This is a new object that constrains the Web worker from accessing any shared memory (like the DOM) with the UI thread that isn’t allowed during normal execution. To illustrate this, simply add a watch for self.
Screen shot showing F12 developer tools’ Watch tab
Debugging multiple script contexts
Because the F12 tools are aware of every currently running script context, it can ask all other script engines to pause while you’re sitting at a breakpoint. This creates a predictable debugging experience because it prevents other script contexts from interacting with the one you’re currently debugging.
Furthermore, you’re also not confined to debugging one script context at a time. Continuing execution from a breakpoint (either within a worker or the UI thread) will resume all script contexts, allowing them to run until another breakpoint is hit (or a debugger statement or exception is encountered). This allows you to automatically switch “focus” from a worker’s script context to the UI thread’s context, making it trivial to debug the interaction between them.
Screen shot showing F12 developer tools’ Call Stack tab
Profiling worker activity and network requests
In addition to debugging, you can also use the profiler to determine the performance of a running worker as you would any other script. Select the Profiler tab in the F12 tools, click Start profiling, and run the script you want to profile. Once done, click Stop profiling in the F12 tools. Here’s a view after selecting Call tree from the Current view drop-down.
Screen shot showing F12 developer tools’ Profiler tab
Notice that the URL column indicates which script the individual activity came from. For instance, with this, we can spot that less time was spent executing the tests inside the worker (execute function inside worker) as compared to the time spent executing these tests on the UI thread (time taken by run function in the UI thread).
Workers also contribute to the overall network activity, since the browser needs to download the script the worker executes, as well as any child scripts they depend on (downloaded via importScripts). All you need to do is select the Network tab and click the Start capturing button. Here’s a screenshot of a capture that included a worker-initiated script request.
Screen shot showing F12 developer tools’ Network tab
Notice that the download request for the worker.js file shows up, but more interestingly, it has its Initiator column indicating why it was downloaded: because of a Web worker. Additionally, the 15.2.js file, which was imported by the worker, also shows up, and indicates that it was initiated by means of a call to the importScripts method.
We welcome your feedback! If you find any issues using Web Workers or its tooling functionality in IE10, please let us know via Connect.
—Jonathan Carter and Gaurav Seth, Program Managers, Browser Programmability & Tools