Web workers: errors and debugging

I’ve been continuing to experiment with web workers this past weekend and found some more interesting information. It seems that the earlier implementers, Firefox 3.5 and Safari 4, have some quirky differences in their capabilities and behaviors. I discovered this as I was trying to figure out what would happen if an error was thrown inside of a worker.

The onerror event handler

The web workers specification indicates that an error event should be fired when a JavaScript error occurs in a worker. The event object passed into the onerror handler is supposed to contain three important properties: message, which is the error message, lineno, which is the line within the worker that threw the error, and filename, which is the JavaScript file in which the error occurred. That should give you enough information to deal with any error that occurs. Example:

Safari’s implementation of web workers doesn’t fire an error event when an error occurs (bug), making it nearly impossible to recover from an error in a worker. Firefox’s implementation does fire the error event, but the message property on the event object isn’t filled in (bug).

Debugging workers

Both Safari and Firefox recognize errors in workers and therefore output them into their respective consoles. This is the good news: you can be aware that an error has occurred. The bad news is that you have no real way of debugging.

Neither Firebug nor Safari’s Web Inspector show worker JavaScript files in their list of loaded scripts. This actually makes sense because the script is not loaded into the page’s global scope and therefore doesn’t register as in use. Even though it makes sense, it also makes debugging worker code incredibly painful.Â Remember what debugging JavaScript was like before Firebug? You’re right back there, except it’s worse.

Since worker code runs in its own global scope separate from the page’s global scope, it means you don’t have access to the console object. No more console.log() to help you figure out what’s going on. You may be thinking that you’ll have to go back to using alert(), like the good ol’ days. Bad news: alert() is a method of window and therefore isn’t available inside of a worker.

Faking it

Without functional onerror event handlers, and without access to our common debugging techniques, it’s necessary to overload the one event that actually works in both Safari and Firefox: the message event. An ideal setup would look like this:

In this model, an object is passed back from the worker via postMessage(). The object has a field, type, that indicates the message is for debugging purposes, and a message field containing the debugging message. This is then read by the page through the onmessage event handler and then the debugging message is output to the console. Note that I said this was the ideal scenario given the uselessness of onerror. Unfortunately, this can’t be used because Safari only supports passing strings via postMessage() (bug). That means the messages can only be strings for a cross-browser implementation, leading to something like this:

This version uses a very primitive string format with a colon separate to pass messages back and forth (if Safari 4 natively supported JSON, that would be another option). Each onmessage handler needs to parse the incoming message to determine what to do and then take the appropriate action. A bit hacky, but gets the job done.

Conclusion

Web workers are still under development and have a lot of potential, but right now there’s a lot of problems. The cross-browser differences are almost crippling and the lack of debugging capabilities lead me to believe that workers are not yet ready for enterprise usage. No one can afford to spend time trying to figure out why their worker isn’t working (pun intended) when deadlines are looming. Perhaps the next iterations on each browser will yield better and more reasonable opportunities for adoption. The full adoption story will ultimately be determined, in my opinion, by the extent to which our debugging tools integrate with workers.

Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.

Related Posts

Subscribe to the mailing list

Email Address

Send me:

Blog posts

Updates

http://ajile.net/ Michael Lee

Nice writeup Nick.

Always detailed and clearly explained.

I haven’t played with web workers as yet so I really appreciate you taking the time to go through the various implementations and share your findings. This post will be a good reference if I get into it before the onerror issues are resolved.

Question? Couldn’t use json2.js to stringify a json error object, postMessage the string, then jsonify again on the receiving end? Could be a cleaner workaround for Safari…

Keep up the great posts. I’ve been following your writings for quite some time and hope you’ll keep at it.

nunchucks

json2.js works fine from within a web worker, and i’m using that exact technique for communication between the main program and the workers. it works great.

now doing XMLHttpRequests from within workers is another story, and I have run into platform-specific issues that are preventing that feature from working everywhere Firefox does.

http://j5bot.blogspot.com J5

Was just doing some tests on nested workers in Safari 4 and they were failing on me. Thought you might be interested in the report.

Have you done any tests of the nested workers, importScripts and XMLHttpRequest support that the API calls for?