setInterval, are actually single threaded. They may be time delayed, but once they’re running, everything else has to wait its turn.
Why Web Workers?
Check out this single threaded demo to witness this terribleness in action.
Now let’s use web workers to offload the intensive code to a background thread, giving the UI thread room to breath. Check out this multi-threaded demo. Much better!
A Simple Code Example
And the other (we’ll name it worker.js) will run in a background thread:
main.js instantiates the worker object with the URL for worker.js (this example assumes they’re sitting side by side). Both files set up their own message listeners, each with a callback to their own
receiveMessage function. This is how the UI thread and background thread communicate: via messaging. They both listen for messages from each other and can post messages to each other.
The final line of main.js is what kicks things off. Here’s the flow:
- main.js messages ‘cowboy’ to worker.js
- worker.js receives the message, handles it by doing a little string concatenation, then messages ‘Sup, cowboy?’ back to main.js
- main.js receives this message and handles it by logging ‘Sup, cowboy?’ to the console
The sample code above uses very simple data (just a string) for each message, but you can send more complex data like so:
In this case, the web worker could access the occupation value via
e.data.occupation. Yeah, it’s just JSON. Also, you can’t send functions via messaging.
Terms and Conditions Apply
As mentioned before, web workers must be put into their own file. This is because their code lives in a completely separate context than any code that exists in the UI thread. It’s a different world and only messaging can cross the divide. There are no shared global variables. Even the data sent via
postMessage is not shared; it’s cloned.
Web workers do not use
window (they use
And here’s a biggie: web workers cannot access the DOM. After all, that’s the territory of the UI thread. Instead, your web worker should post a message to the UI thread telling it to make any DOM updates.
Browser support is decent. IE10+, Android 2.1 and 4.4+ (yeah, it was removed for a while, weird eh?) and then all the other major players.
By default, debugging web workers can be difficult. For example, put a breakpoint in your web worker, run your code, and… watch it be ignored. Fortunately, this is easy to fix. If you’re using Chrome, open up the dev tools, go to the Sources tab, and check this checkbox:
Now try again. You’ll see a second dev tools window pop up when your web worker is instantiated. Now you have a window into your background thread. Set your breakpoints there and debug to your heart’s content.
I’ll leave you with something fun: a board game played against the computer (hint: it’s Connect Four). Yep, I’ve blogged about this one before. The computer can take a while to think on higher difficulty levels, so I offload all of that thinking to a web worker. This allows the UI thread to stay responsive and show progress (the chip moving across the top) during the computer’s turn.