By: Craig Buckler
Your web browser and the web page you’re viewing share a single processing thread. When an event occurs within the page or browser interface, the handler is added to a single queue. The next time the browser becomes idle, the next handler on the queue is processed.
Browsers will not permit your script to run for too long since it prevents the user interacting with the application. Problems can therefore occur if you have a long-running or process-intensive task. Consider this simple example:
It performs one billion simple operations but is unlikely to get that far…
How to Browsers Detect Unresponsive Scripts?
The vendors use different methods to assess browser responsiveness:
IE limits execution to a number statements
Firefox and Safari limit execution to a number of seconds
Chrome and Opera 15+ detect when the browser becomes unresponsive
You cannot accurately determine when an “unresponsive script” error will be fired because computer processing speeds, operating systems and browsers vary. I would suggest any code which runs for more than a second on an average PC is at risk.
Ideally, web-based applications should not use long-running scripts. Web pages are event-driven; the user performs an action and the client-side code reacts. If your application requires intensive processes, there may be a better solution such as pre-calculation or offloading to the server. If that is not an option, you may need to consider threading.
What is Threading?
A thread is a separate process normally managed by your operating system. Modern OSs are inherently multi-threaded since you can run more than one application at a time. Each program can perform its own tasks without waiting for another to stop.
Multi-core processors can run more than one thread concurrently but hundreds of threads could be required. Therefore the OS switches between different processes; a thread is executed for a short time before switching to the next one.
Web Worker code must be available on the same origin (domain) as the parent process which calls them.
Web Worker threads operate independently of the browser UI; they cannot access or modify the page DOM.
Access to some browser objects is restricted, e.g. window.location properties are read-only.
Web Workers may only communicate with your main page by receiving and returning a single parameter – although that can be an object or an array containing many items.
Web Workers are event-driven; you must write code to respond to asynchronous events in both your calling application and the Web Worker code
Web Workers are supported in Firefox, Chrome, Safari, Opera and IE10+.
We’ll re-write our large loop program to use Web Workers:
This code performs the following actions:
First, we check if Web Workers are supported in the browser by checking for the existence of the window.Worker object.
A new handler function is defined for the onmessage event. This is executed when the Web Worker completes its work and returns an object, e. The data property is the returned message.
Finally, we start the Web Worker thread with the postMessage method. In this code, we’re passing the size of the loop as an argument.
Our Web Worker code is now defined in webworker.js (the filename we used above):
This implements a single event handler which waits for a message sent from the calling application when it executes the postMessage method. The function:
• is passed a message object, e, which contains our parameter (999999999) in the data property.
The loop then runs within the background process.
Finally, we can return the processing result to the calling application using another postMessage method call. This runs the onmessage handler function defined in the page above.
You will not experience any “unresponsive script” errors because webworker.js runs as a background process. As a bonus, the script generally executes faster because the browser runs it in a more limited context which is not able to communicate with the DOM.
There are a number of further points you should note about Web Workers:
Web Workers can import other scripts using the importScripts(“filename”) command. Multiple files can be imported by separating each name string with a comma.
You can spawn any number of Web Workers; each can spawn any number of sub-workers and so on. The script URI for sub-workers is relative to the parent worker’s location rather than the root page.
If you need to stop a Web Worker from your main page, you can use the terminate() method, e.g. thread.terminate();
Web Workers may terminate themselves using the close() method, e.g. self.close();
If an error occurs within a Web Worker, an onerror handler is called and passed an error event object which exposes properties including filename, message and lineno, e.g.
Web Workers are not supported in older browsers. While shims are available, they only implement the Web Worker API and cannot execute background processes. “Unresponsive Script” errors could still occur.
This runs myfunction() after approximately 50 milliseconds but, importantly, the browser is freed to perform other tasks during that time.
If we need to run a series of process-intensive functions, we can add a delay between them, e.g.
However, these functions may not be called in the order you expect. To rectify that issue, we can create a function to handle calling in sequence:
Using timers is not perfect since a single function could result in an “Unresponsive Script” error, however, this may be the best option if support for older browsers is essential.
Check out more courses and tutorials: