HTML5 introduced Web Worker to solve the problem of Javascript concurrency. In the past, developers have to mimic "concurrency" by using techniques like setTimeout(), setInterval, XMLHttpRequest, and event handlers. However, all of these features run asynchronously, non-blocking does not mean concurrency. Asynchronous events are processed after current executing script has yielded.
Web Worker allows you to do things like fire up long-running script to handle computationally intensive tasks, but without blocking UI or other scripts to handle user iteractions. Worker utlize thread-like message to passing to achieve parallelism.
Types of Worker
There are two kinds of Workers: Dedicated Worker and Shared Workers. But Shared Workers is not supported perfectly by now. So, we only cover Dedicated Workers here.
Get Started
Web Workers are run in a separated thread. As a result, the code they executed needs to be contained in a separated file. We can create a new Worker instance like this:
var worker = new Worker("task.js");
If the script file exists, the browser will sprawn a worker thread, which will download the script file asynchronously. The worker will not begin until the file is downladed and executed. If the path returns 404, the worker will fail silently.
After the worker begining, start it by calling postMessage() method.
worker.postMessage(); // start the worker
Communicating with a Worker via Message Passing
Communication between a work and its parent page is done by using an event model and the postMessage() method. Depending on your browser/version, postMessage() can accept either a string or JSON object as its single argument. The latest versions of the modern browsers support passing a JSON object.
Below is a example of using a string to pass 'Hello World' to a worker in doWork.js. The worker simply returns the message that is passed to it.
Main script:
var worker = new Worker('doWork.js'); worker.addEventListener('message', function(e) { console.log('Worker said: ', e.data); }, false); worker.postMessage('Hello World'); // Send data to our worker.
doWork.js (the worker):
self.addEventListener('message', function(e) {
self.postMessage(e.data);
}, false);
When postMessage() is called from the main page, our worker handles that message by defining an onmessage handler for the message event. The message payload (in this case 'Hello World') is accessible in Event.data. Although this particular example isn't very exciting, it demonstrates that postMessage() is also your means for passing data back to the main thread. Convenient!
Messages passed between the main page and workers are copied, not shared. For example, in the next example the 'msg' property of the JSON message is accessible in both locations. It appears that the object is being passed directly to the worker even though it's running in a separate, dedicated space. In actuality, what is happening is that the object is being serialized as it's handed to the worker, and subsequently, de-serialized on the other end. The page and worker do not share the same instance, so the end result is that a duplicate is created on each pass. Most browsers implement this feature by automatically JSON encoding/decoding the value on either end.
Works Can/Can't do:
Due to muti-thread behavior, works only have access to a subset of Javascript features:
- The navigator object
- The location object (read-only)
- XMLHttpRequest
- setTimeout() / clearTimeout() and
- setInterval() / clearInterval()
- The Application Cache
- Importing external scripts using importScripts() method
- Spawn other Web Workers
Workers do not have the access to
- The DOM
- The window object
- The document object
- The parent object
浙公网安备 33010602011771号