Worker: Worker() constructor
Baseline
Widely available
*
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
* Some parts of this feature may have varying levels of support.
Note: This feature is available in Web Workers, except for Service Workers.
Warning:
This script passed to the url element is executed.
APIs like this are known as injection sinks, and are potentially a vector for cross-site scripting (XSS) attacks.
You can mitigate this risk by having a Content Security Policy (CSP) that restricts the locations from which scripts can be loaded, and by always assigning TrustedScriptURL objects instead of strings and enforcing trusted types.
See Security considerations for more information.
The Worker() constructor creates a Worker object that executes the classic script or module at the specified URL.
Syntax
new Worker(url)
new Worker(url, options)
Parameters
url-
A
TrustedScriptURLobject or a string representing the URL of the script or module that the worker will execute.This must be same-origin with the caller's document, or a
blob:ordata:URL. The URL is resolved relative to the current HTML page's location. optionsOptional-
An object containing option properties that can be set when creating the object instance. Available properties are as follows:
credentials-
A string specifying whether the browser sends credentials when importing modules into a module worker. The allowed values are the same as can be passed to the
fetch()request:omit,same-origin, orinclude. The default issame-origin(only include credentials for same-origin requests).This is ignored for classic workers.
name-
A string specifying an identifying name for the
DedicatedWorkerGlobalScoperepresenting the scope of the worker, which is mainly useful for debugging purposes. type-
A string specifying the type of worker to create. The value can be
classicormodule. The default isclassic.
Exceptions
NetworkErrorDOMException-
Thrown if the MIME type of the worker script is incorrect. It should always be
text/javascript(for historical reasons other JavaScript MIME types may be accepted). SecurityErrorDOMException-
Thrown if the document is not allowed to start workers, e.g., if the URL has an invalid syntax or if the same-origin policy is violated.
SyntaxErrorDOMException-
Thrown if
urlcannot be parsed. TypeError-
Thrown if the
urlparameter is a string when Trusted Types are enforced by a CSP and no default policy is defined.
Description
The Worker() constructor creates a Worker object that executes the classic script or module at the specified URL.
The script must be same-origin with the associated document, but may itself import scripts or modules that are cross-origin (if permitted by CORS and other restrictions). If a cross-origin worker is required, users must load it from an intermediate same-origin worker or a blob.
Module and classic workers
A classic worker is one that that is constructed from a classic script, while a module worker is constructed from an ECMASCript module. The type of worker affects the worker constructor options, how the worker script is fetched, and how it is executed.
The code below shows two ways you can construct a classic worker, and also how you specify the type of "module" to create a module worker.
In both cases the script must be same-origin with the loading document and is resolved relative to the location of the launching document.
// Construct a classic worker
const worker1 = new Worker("worker_classic.js");
const worker2 = new Worker("worker_classic.js", {
type: "classic",
});
// Construct a module worker
const worker3 = new Worker("worker_module.js", {
type: "module",
});
Module workers and their dependencies are loaded and executed using ECMAScript module semantics:
- Dependencies are imported via static
importstatements - Fetched asynchronously using CORS.
- All modules are resolved before any code is executed
- Must be served with the media type
Content-Type: text/javascript - Executed in Strict mode
Classic workers are fetched and executed as scripts:
- Dependencies are imported using the
WorkerGlobalScope.importScripts()method - Fetched synchonously in
no-corsmode
Importing scripts or modules
Module workers can import ECMASCript modules using import statements.
Modules are fetched using CORS, so cross-origin modules must be served with the Access-Control-Allow-Origin header in order to be loaded.
Developers can specify whether or not credentials should be sent in cross-origin imports.
Classic workers can import scripts (but not modules) using the WorkerGlobalScope.importScripts() method.
Unlike modules, scripts are fetched in no-cors mode, and can be requested cross-origin even if the server does not set the appropriate CORS headers.
Credentials are sent for same-origin imports, but are usually not sent for cross-origin requests.
In addition, if the document has a Content Security Policy (CSP), it must allow the origins of imported scripts or modules.
For modules the allowed sources are specified in worker-src (with fallback to script-src and default-src directives), while for classic scripts the sources are specified in script-src (with fallback to the default-src directives).
data: and blob: URLs
data: URLs can be passed to the url parameter, but have an opaque_origin, which makes them cross-origin to all other origins including their owner.
Consequently, while the worker can still communicate with its owner using postMessage(), it's access to other external resources is highly restricted.
For example, a worker fetch() request would be cross-origin to its own site, and any requests to any origin must be granted by CORS.
blob: URLs should be used instead, where possible, because the URL inherits the origin of the document that created it.
This ensures that a worker created with a blob: URL is same-origin with the page that created it.
Note that if you're using a Content Security Policy (CSP) to restrict what resources can be loaded into your worker, you will need to allow the blob: origin.
Bundler considerations
Bundlers such as webpack, Vite, and Parcel, recommend passing URLs that are relative to import.meta.url to the Worker() constructor.
For example:
const myWorker = new Worker(new URL("worker.js", import.meta.url));
This makes the path relative to the current script instead of the current HTML page, which allows the bundler to safely do optimizations like renaming (because otherwise the worker.js URL may point to a file not controlled by the bundler, so it cannot make any assumptions).
Security considerations
The script or module specified by the url argument is executed in the web worker context, and may itself import other same-origin and cross-origin scripts.
If the url is provided by a user, this is a possible vector for cross-site scripting (XSS) attacks.
While web workers do not have direct access to the owning document or window, it is still extremely risky to accept and execute arbitrary URLs from untrusted origins. For module workers, but not classic workers, CORS will control what cross-origin resources can be requested.
A website should also control what scripts that are allowed to run using a Content Security Policy (CSP) with the worker-src directive (or a fallback to child-src, script-src, or default-src).
This can restrict scripts to those from the current origin, or a specific set of origins, or even particular files.
If you're using this property and enforcing trusted types (using the require-trusted-types-for CSP directive), you will need to always assign TrustedScriptURL objects instead of strings.
This ensures that the input is passed through a transformation function, which has the chance to reject or modify URLs needed by the worker before they are fetched.
Examples
For brevity, only the first example below uses trusted types. In production your code should always use trusted types when passing data originating from users into injection sinks.
Using Trusted Types
To mitigate the risk of XSS, we should always pass TrustedScriptURL instances to the worker URL instead of strings.
We also need to do this if we're enforcing trusted types for other reasons and we want to allow some sources that have been permitted (by CSP: worker-src).
Trusted types are not yet supported on all browsers, so first we define the trusted types tinyfill. This acts as a transparent replacement for the trusted types JavaScript API:
if (typeof trustedTypes === "undefined")
trustedTypes = { createPolicy: (n, rules) => rules };
Next we create a TrustedTypePolicy that defines a createScriptURL() method for transforming input strings into TrustedScriptURL instances.
For the purpose of this example we'll assume that we want to allow a predefined set of URLs in the workerScriptAllowList array and log any other scripts.
const workerScriptAllowList = [
// Some list of allowed URLs
];
const policy = trustedTypes.createPolicy("worker-url-policy", {
createScriptURL(input) {
if (workerScriptAllowList.includes(input)) {
return input; // allow the script
}
console.log(`Script not in workerScriptAllowList: ${input}`);
return ""; // Block the script
},
});
Next we use our policy object to create a trustedScriptURL object from a potentially unsafe input string and pass this to the worker.
// The potentially malicious worker URL
// We won't be including untrustedScript in our workerScriptAllowList array
const untrustedScriptURL = "https://evil.example.com/naughty.js";
// Create a TrustedScriptURL instance using the policy
const trustedScriptURL = policy.createScriptURL(untrustedScriptURL);
// Construct the worker with the trusted URL
const myWorker = new Worker(trustedScriptURL);
Creating a classic worker
The following code snippet shows creation of a classic Worker object using the Worker() constructor, and subsequent usage of the object:
const myWorker = new Worker("worker.js");
const first = document.querySelector("input#number1");
first.onchange = () => {
myWorker.postMessage(first.value);
console.log("Message posted to worker");
};
For a full example, see our Basic dedicated worker example (run dedicated worker).
Loading a cross-origin module worker from a blob
This example shows a method that can fetch and load a cross-origin module worker script and then load it into your worker as a blob (a classic script could be loaded in the same way):
async function loadWorker() {
const response = await fetch("https://other_origin.com/worker.js");
const script = await response.text();
// Create a blob that contains the fetched script, and then create a URL from that blob
const blob = new Blob([script], { type: "application/javascript" });
const workerUrl = URL.createObjectURL(blob);
try {
const worker = new Worker(workerUrl, { type: "module" });
} catch (e) {
console.error(`Cross-origin worker module failed to load: ${e}`);
}
}
loadWorker();
The initial fetch is made with CORS, and so the other_origin.com response will need to include the Access-Control-Allow-Origin header as shown:
Access-Control-Allow-Origin "https://my_origin.com"
In addition, if you're using a CSP you will need to allow the blob: origin for worker-src so that it can be loaded into the document:
Content-Security-Policy worker-src 'self' https://other_origin.com blob:
Specifications
| Specification |
|---|
| HTML> # dom-worker-dev> |