Using Web Workers - Web APIs

Using Web Workers
=================

Web Workers are a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface. In addition, they can make network requests using the `fetch()` or `XMLHttpRequest` APIs. Once created, a worker can send messages to the JavaScript code that created it by posting messages to an event handler specified by that code (and vice versa).

This article provides a detailed introduction to using web workers.

Web Workers API
---------------

A worker is an object created using a constructor (e.g. `Worker()`) that runs a named JavaScript file — this file contains the code that will run in the worker thread; workers run in another global context that is different from the current `window`. Thus, using the `window` shortcut to get the current global scope (instead of `self`) within a `Worker` will return an error.

The worker context is represented by a `DedicatedWorkerGlobalScope` object in the case of dedicated workers (standard workers that are utilized by a single script; shared workers use `SharedWorkerGlobalScope`). A dedicated worker is only accessible from the script that first spawned it, whereas shared workers can be accessed from multiple scripts.

**Note:** See The Web Workers API landing page for reference documentation on workers and additional guides.

You can run whatever code you like inside the worker thread, with some exceptions. For example, you can't directly manipulate the DOM from inside a worker, or use some default methods and properties of the `window` object. But you can use a large number of items available under `window`, including WebSockets, and data storage mechanisms like IndexedDB. See Functions and classes available to workers for more details.

Data is sent between workers and the main thread via a system of messages — both sides send their messages using the `postMessage()` method, and respond to messages via the `onmessage` event handler (the message is contained within the `message` event's data attribute). The data is copied rather than shared.

Workers may in turn spawn new workers, as long as those workers are hosted within the same origin as the parent page.

In addition, workers can make network requests using the `fetch()` or `XMLHttpRequest` APIs (although note that the `responseXML` attribute of `XMLHttpRequest` will always be `null`).

Dedicated workers
-----------------

As mentioned above, a dedicated worker is only accessible by the script that called it. In this section we'll discuss the JavaScript found in our Basic dedicated worker example (run dedicated worker): This allows you to enter two numbers to be multiplied together. The numbers are sent to a dedicated worker, multiplied together, and the result is returned to the page and displayed.

This example is rather trivial, but we decided to keep it simple while introducing you to basic worker concepts. More advanced details are covered later on in the article.

### Worker feature detection

For slightly more controlled error handling and backwards compatibility, it is a good idea to wrap your worker accessing code in the following (main.js):

```js
if (window.Worker) {
  // …
}
```

### Spawning a dedicated worker

Creating a new worker is simple. All you need to do is call the `Worker()` constructor, specifying the URI of a script to execute in the worker thread (main.js):

```js
const myWorker = new Worker("worker.js");
```

### Sending messages to and from a dedicated worker

The magic of workers happens via the `postMessage()` method and the `onmessage` event handler. When you want to send a message to the worker, you post messages to it like this (main.js):

```js
first.onchange = () => {
  myWorker.postMessage([first.value, second.value]);
  console.log("Message posted to worker");
};

second.onchange = () => {
  myWorker.postMessage([first.value, second.value]);
  console.log("Message posted to worker");
};
```

So here we have two `<input>` elements represented by the variables `first` and `second`; when the value of either is changed, `myWorker.postMessage([first.value,second.value])` is used to send the value inside both to the worker, as an array. You can send pretty much anything you like in the message.

In the worker, we can respond when the message is received by writing an event handler block like this (worker.js):

```js
onmessage = (e) => {
  console.log("Message received from main script");
  const workerResult = `Result: ${e.data[0] \* e.data[1]}`;
  console.log("Posting message back to main script");
  postMessage(workerResult);
};
```

The `onmessage` handler allows us to run some code whenever a message is received, with the message itself being available in the `message` event's `data` attribute. Here we multiply together the two numbers then use `postMessage()` again, to post the result back to the main thread.

Back in the main thread, we use `onmessage` again, to respond to the message sent back from the worker:

```js
myWorker.onmessage = (e) => {
  result.textContent = e.data;
  console.log("Message received from worker");
};
```

Here we grab the message event data and set it as the `textContent` of the result paragraph, so the user can see the result of the calculation.

**Note:** Notice that `onmessage` and `postMessage()` need to be hung off the `Worker` object when used in the main script thread, but not when used in the worker. This is because, inside the worker, the worker is effectively the global scope.

**Note:** When a message is passed between the main thread and worker, it is copied or "transferred" (moved), not shared. Read Transferring data to and from workers: further details for a much more thorough explanation.

### Terminating a worker

If you need to immediately terminate a running worker from the main thread, you can do so by calling the worker's `terminate` method:

```js
myWorker.terminate();
```

The worker thread is killed immediately.

### Handling errors

When a runtime error occurs in the worker, its `onerror` event handler is called. It receives an event named `error` which implements the `ErrorEvent` interface.

The event doesn't bubble and is cancelable; to prevent the default action from taking place, the worker can call the error event's `preventDefault()` method.

The error event has the following three fields that are of interest:

`message`

A human-readable error message.

`filename`

The name of the script file in which the error occurred.

`lineno`

The line number of the script file on which the error occurred.

### Spawning subworkers

Workers may spawn more workers if they wish. So-called sub-workers must be hosted within the same origin as the parent page. Also, the URIs for subworkers are resolved relative to the parent worker's location rather than that of the owning page. This makes it easier for workers to keep track of where their dependencies are.

### Importing scripts and libraries

Worker threads have access to a global function, `importScripts()`, which lets them import scripts. It accepts zero or more URIs as parameters to resources to import; all the following examples are valid:

```js
importScripts(); /\* imports nothing \*/
importScripts("foo.js"); /\* imports just "foo.js" \*/
importScripts("foo.js", "bar.js"); /\* imports two scripts \*/
importScripts(
  "//example.com/hello.js",
); /\* You can import scripts from other origins \*/
```

The browser loads each listed script and executes it. Any global objects from each script may then be used by the worker. If the script can't be loaded, `NETWORK_ERROR` is thrown, and subsequent code will not be executed. Previously executed code (including code deferred using `setTimeout()`) will still be functional though. Function declarations **after** the `importScripts()` method are also kept, since these are always evaluated before the rest of the code.

**Note:** Scripts may be downloaded in any order, but will be executed in the order in which you pass the filenames into `importScripts()`. This is done synchronously; `importScripts()` does not return until all the scripts have been loaded and executed.

Shared workers
--------------

A shared worker is accessible by multiple scripts — even if they are being accessed by different windows, iframes or even workers. In this section we'll discuss the JavaScript found in our Basic shared worker example (run shared worker): This is very similar to the basic dedicated worker example, except that it has two functions available handled by different script files: *multiplying two numbers*, or *squaring a number*. Both scripts use the same worker to do the actual calculation required.

Here we'll concentrate on the differences between dedicated and shared workers. Note that in this example we have two HTML pages, each with JavaScript applied that uses the same single worker file.

**Note:** If SharedWorker can be accessed from several browsing contexts, all those browsing contexts must share the exact same origin (same protocol, host, and port).

**Note:** In Firefox, shared workers cannot be shared between documents loaded in private and non-private windows (Firefox bug 1177621).

### Spawning a shared worker

Spawning a new shared worker is pretty much the same as with a dedicated worker, but with a different constructor name (see index.html and index2.html) — each one has to spin up the worker using code like the following:

```js
const myWorker = new SharedWorker("worker.js");
```

One big difference is that with a shared worker you have to communicate via a `port` object — an explicit port is opened that the scripts can use to communicate with the worker (this is done implicitly in the case of dedicated workers).

The port connection needs to be started either implicitly by use of the `onmessage` event handler or explicitly with the `start()` method before any messages can be posted. Calling `start()` is only needed if the `message` event is wired up via the `addEventListener()` method.

**Note:** When using the `start()` method to open the port connection, it needs to be called from both the parent thread and the worker thread if two-way communication is needed.

### Sending messages to and from a shared worker

Now messages can be sent to the worker as before, but the `postMessage()` method has to be invoked through the port object (again, you'll see similar constructs in both multiply.js and square.js):

```js
squareNumber.onchange = () => {
  myWorker.port.postMessage([squareNumber.value, squareNumber.value]);
  console.log("Message posted to worker");
};
```

Now, on to the worker. There is a bit more complexity here as well (worker.js):

```js
onconnect = (e) => {
  const port = e.ports[0];

  port.onmessage = (e) => {
    const workerResult = `Result: ${e.data[0] \* e.data[1]}`;
    port.postMessage(workerResult);
  };
};
```

First, we use an `onconnect` handler to fire code when a connection to the port happens (i.e. when the `onmessage` event handler in the parent thread is set up, or when the `start()` method is explicitly called in the parent thread).

We use the `ports` attribute of this event object to grab the port and store it in a variable.

Next, we add an `onmessage` handler on the port to do the calculation and return the result to the main thread. Setting up this `onmessage` handler in the worker thread also implicitly opens the port connection back to the parent thread, so the call to `port.start()` is not actually needed, as noted above.

Finally, back in the main script, we deal with the message (again, you'll see similar constructs in both multiply.js and square.js):

```js
myWorker.port.onmessage = (e) => {
  result2.textContent = e.data;
  console.log("Message received from worker");
};
```

When a message comes back through the port from the worker, we insert the calculation result inside the appropriate result paragraph.

About thread safety
-------------------

The `Worker` interface spawns real OS-level threads, and mindful programmers may be concerned that concurrency can cause "interesting" effects in your code if you aren't careful.

However, since web workers have carefully controlled communication points with other threads, it's actually very hard to cause concurrency problems. There's no access to non-threadsafe components or the DOM. And you have to pass specific data in and out of a thread through serialized objects. So you have to work really hard to cause problems in your code.

Content security policy
-----------------------

Workers are considered to have their own execution context, distinct from the document that created them. For this reason they are, in general, not governed by the content security policy of the document (or parent worker) that created them. So for example, suppose a document is served with the following header:

```http
Content-Security-Policy: script-src 'self'
```

Among other things, this will prevent any scripts it includes from using `eval()`. However, if the script constructs a worker, code running in the worker's context *will* be allowed to use `eval()`.

To specify a content security policy for the worker, set a Content-Security-Policy response header for the request which delivered the worker script itself.

The exception to this is if the worker script's origin is a globally unique identifier (for example, if its URL has a scheme of data or blob). In this case, the worker does inherit the CSP of the document or worker that created it.

Transferring data to and from workers: further details
------------------------------------------------------

Data passed between the main page and workers is **copied**, not shared. Objects are serialized as they're 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 end. Most browsers implement this feature as structured cloning.

To illustrate this, let's create a function named `emulateMessage()`, which will simulate the behavior of a value that is *cloned and not shared* during the passage from a `worker` to the main page or vice versa:

```js
function emulateMessage(vVal) {
  return eval(`(${JSON.stringify(vVal)})`);
}

// Tests

// test #1
const example1 = new Number(3);
console.log(typeof example1); // object
console.log(typeof emulateMessage(example1)); // number

// test #2
const example2 = true;
console.log(typeof example2); // boolean
console.log(typeof emulateMessage(example2)); // boolean

// test #3
const example3 = new String("Hello World");
console.log(typeof example3); // object
console.log(typeof emulateMessage(example3)); // string

// test #4
const example4 = {
  name: "Carina Anand",
  age: 43,
};
console.log(typeof example4); // object
console.log(typeof emulateMessage(example4)); // object

// test #5
function Animal(type, age) {
  this.type = type;
  this.age = age;
}
const example5 = new Animal("Cat", 3);
alert(example5.constructor); // Animal
alert(emulateMessage(example5).constructor); // Object
```

A value that is cloned and not shared is called *message*. As you will probably know by now, *messages* can be sent to and from the main thread by using `postMessage()`, and the `message` event's `data` attribute contains data passed back from the worker.

**example.html**: (the main page):

```js
const myWorker = new Worker("my\_task.js");

myWorker.onmessage = (event) => {
  console.log(`Worker said : ${event.data}`);
};

myWorker.postMessage("ali");
```

**my\_task.js** (the worker):

```js
postMessage("I'm working before postMessage('ali').");

onmessage = (event) => {
  postMessage(`Hi, ${event.data}`);
};
```

The structured cloning algorithm can accept JSON and a few things that JSON can't — like circular references.

### Passing data examples

#### Example 1: Advanced passing JSON Data and creating a switching system

If you have to pass some complex data and have to call many different functions both on the main page and in the Worker, you can create a system which groups everything together.

First, we create a `QueryableWorker` class that takes the URL of the worker, a default listener, and an error handler, and this class is going to keep track of a list of listeners and help us communicate with the worker:

```js
function QueryableWorker(url, defaultListener, onError) {
  const instance = this;
  const worker = new Worker(url);
  const listeners = {};

  this.defaultListener = defaultListener ?? (() => {});

  if (onError) {
    worker.onerror = onError;
  }

  this.postMessage = (message) => {
    worker.postMessage(message);
  };

  this.terminate = () => {
    worker.terminate();
  };
}
```

Then we add the methods of adding/removing listeners:

```js
this.addListeners = (name, listener) => {
  listeners[name] = listener;
};

this.removeListeners = (name) => {
  delete listeners[name];
};
```

Here we let the worker handle two simple operations for illustration: getting the difference of two numbers and making an alert after three seconds. In order to achieve that we first implement a `sendQuery` method which queries if the worker actually has the corresponding methods to do what we want.

```js
// This functions takes at least one argument, the method name we want to query.
// Then we can pass in the arguments that the method needs.
this.sendQuery = (queryMethod, ...queryMethodArguments) => {
  if (!queryMethod) {
    throw new TypeError(
      "QueryableWorker.sendQuery takes at least one argument",
    );
  }
  worker.postMessage({
    queryMethod,
    queryMethodArguments,
  });
};
```

We finish QueryableWorker with the `onmessage` method. If the worker has the corresponding methods we queried, it should return the name of the corresponding listener and the arguments it needs, we just need to find it in `listeners`.:

```js
worker.onmessage = (event) => {
  if (
    event.data instanceof Object &&
    Object.hasOwn(event.data, "queryMethodListener") &&
    Object.hasOwn(event.data, "queryMethodArguments")
  ) {
    listeners[event.data.queryMethodListener].apply(
      instance,
      event.data.queryMethodArguments,
    );
  } else {
    this.defaultListener.call(instance, event.data);
  }
};
```

Now onto the worker. First we need to have the methods to handle the two simple operations:

```js
const queryableFunctions = {
  getDifference(a, b) {
    reply("printStuff", a - b);
  },
  waitSomeTime() {
    setTimeout(() => {
      reply("doAlert", 3, "seconds");
    }, 3000);
  },
};

function reply(queryMethodListener, ...queryMethodArguments) {
  if (!queryMethodListener) {
    throw new TypeError("reply - takes at least one argument");
  }
  postMessage({
    queryMethodListener,
    queryMethodArguments,
  });
}

/\* This method is called when main page calls QueryWorker's postMessage method directly\*/
function defaultReply(message) {
  // do something
}
```

And the `onmessage` method is now trivial:

```js
onmessage = (event) => {
  if (
    event.data instanceof Object &&
    Object.hasOwn(event.data, "queryMethod") &&
    Object.hasOwn(event.data, "queryMethodArguments")
  ) {
    queryableFunctions[event.data.queryMethod].apply(
      self,
      event.data.queryMethodArguments,
    );
  } else {
    defaultReply(event.data);
  }
};
```

Here are the full implementation:

**example.html** (the main page):

```html
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>MDN Example - Queryable worker</title>
    <script type="text/javascript">
 // QueryableWorker instances methods:
 // \* sendQuery(queryable function name, argument to pass 1, argument to pass 2, etc. etc.): calls a Worker's queryable function
 // \* postMessage(string or JSON Data): see Worker.prototype.postMessage()
 // \* terminate(): terminates the Worker
 // \* addListener(name, function): adds a listener
 // \* removeListener(name): removes a listener
 // QueryableWorker instances properties:
 // \* defaultListener: the default listener executed only when the Worker calls the postMessage() function directly
 function QueryableWorker(url, defaultListener, onError) {
 const instance = this;
 const worker = new Worker(url);
 const listeners = {};

 this.defaultListener = defaultListener ?? (() => {});

 if (onError) {
 worker.onerror = onError;
 }

 this.postMessage = (message) => {
 worker.postMessage(message);
 };

 this.terminate = () => {
 worker.terminate();
 };

 this.addListener = (name, listener) => {
 listeners[name] = listener;
 };

 this.removeListener = (name) => {
 delete listeners[name];
 };

 // This functions takes at least one argument, the method name we want to query.
 // Then we can pass in the arguments that the method needs.
 this.sendQuery = (queryMethod, ...queryMethodArguments) => {
 if (!queryMethod) {
 throw new TypeError(
 "QueryableWorker.sendQuery takes at least one argument",
 );
 }
 worker.postMessage({
 queryMethod,
 queryMethodArguments,
 });
 };

 worker.onmessage = (event) => {
 if (
 event.data instanceof Object &&
 Object.hasOwn(event.data, "queryMethodListener") &&
 Object.hasOwn(event.data, "queryMethodArguments")
 ) {
 listeners[event.data.queryMethodListener].apply(
 instance,
 event.data.queryMethodArguments,
 );
 } else {
 this.defaultListener.call(instance, event.data);
 }
 };
 }

 // your custom "queryable" worker
 const myTask = new QueryableWorker("my\_task.js");

 // your custom "listeners"
 myTask.addListener("printStuff", (result) => {
 document
 .getElementById("firstLink")
 .parentNode.appendChild(
 document.createTextNode(`The difference is ${result}!`),
 );
 });

 myTask.addListener("doAlert", (time, unit) => {
 alert(`Worker waited for ${time} ${unit} :-)`);
 });
 </script>
  </head>
  <body>
    <ul>
      <li>
        <a
 id="firstLink"
 href="javascript:myTask.sendQuery('getDifference', 5, 3);"
 >What is the difference between 5 and 3?</a
 >
      </li>
      <li>
        <a href="javascript:myTask.sendQuery('waitSomeTime');"
 >Wait 3 seconds</a
 >
      </li>
      <li>
        <a href="javascript:myTask.terminate();">terminate() the Worker</a>
      </li>
    </ul>
  </body>
</html>
```

**my\_task.js** (the worker):

```js
const queryableFunctions = {
  // example #1: get the difference between two numbers:
  getDifference(minuend, subtrahend) {
    reply("printStuff", minuend - subtrahend);
  },

  // example #2: wait three seconds
  waitSomeTime() {
    setTimeout(() => {
      reply("doAlert", 3, "seconds");
    }, 3000);
  },
};

// system functions

function defaultReply(message) {
  // your default PUBLIC function executed only when main page calls the queryableWorker.postMessage() method directly
  // do something
}

function reply(queryMethodListener, ...queryMethodArguments) {
  if (!queryMethodListener) {
    throw new TypeError("reply - not enough arguments");
  }
  postMessage({
    queryMethodListener,
    queryMethodArguments,
  });
}

onmessage = (event) => {
  if (
    event.data instanceof Object &&
    Object.hasOwn(event.data, "queryMethod") &&
    Object.hasOwn(event.data, "queryMethodArguments")
  ) {
    queryableFunctions[event.data.queryMethod].apply(
      self,
      event.data.queryMethodArguments,
    );
  } else {
    defaultReply(event.data);
  }
};
```

It is possible to switch the content of each mainpage -> worker and worker -> mainpage message. And the property names "queryMethod", "queryMethodListeners", "queryMethodArguments" can be anything as long as they are consistent in `QueryableWorker` and the `worker`.

### Passing data by transferring ownership (transferable objects)

Modern browsers contain an additional way to pass certain types of objects to or from a worker with high performance. Transferable objects are transferred from one context to another with a zero-copy operation, which results in a vast performance improvement when sending large data sets.

For example, when transferring an `ArrayBuffer` from your main app to a worker script, the original `ArrayBuffer` is cleared and no longer usable. Its content is (quite literally) transferred to the worker context.

```js
// Create a 32MB "file" and fill it with consecutive values from 0 to 255 – 32MB = 1024 \* 1024 \* 32
const uInt8Array = new Uint8Array(1024 \* 1024 \* 32).map((v, i) => i);
worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]);
```

Embedded workers
----------------

There is not an "official" way to embed the code of a worker within a web page, like `<script>` elements do for normal scripts. But a `<script>` element that does not have a `src` attribute and has a `type` attribute that does not identify an executable MIME type can be considered a data block element that JavaScript could use. "Data blocks" is a more general feature of HTML that can carry almost any textual data. So, a worker could be embedded in this way:

```html
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>MDN Example - Embedded worker</title>
    <script type="text/js-worker">
 // This script WON'T be parsed by JS engines because its MIME type is text/js-worker.
 const myVar = 'Hello World!';
 // Rest of your worker code goes here.
 </script>
    <script>
 // This script WILL be parsed by JS engines because its MIME type is text/javascript.
 function pageLog(sMsg) {
 // Use a fragment: browser will only render/reflow once.
 const frag = document.createDocumentFragment();
 frag.appendChild(document.createTextNode(sMsg));
 frag.appendChild(document.createElement("br"));
 document.querySelector("#logDisplay").appendChild(frag);
 }
 </script>
    <script type="text/js-worker">
 // This script WON'T be parsed by JS engines because its MIME type is text/js-worker.
 onmessage = (event) => {
 postMessage(myVar);
 };
 // Rest of your worker code goes here.
 </script>
    <script>
 // This script WILL be parsed by JS engines because its MIME type is text/javascript.

 // In the past blob builder existed, but now we use Blob
 const blob = new Blob(
 Array.prototype.map.call(
 document.querySelectorAll("script[type='text\/js-worker']"),
 (script) => script.textContent,
 ),
 { type: "text/javascript" },
 );

 // Creating a new document.worker property containing all our "text/js-worker" scripts.
 document.worker = new Worker(window.URL.createObjectURL(blob));

 document.worker.onmessage = (event) => {
 pageLog(`Received: ${event.data}`);
 };

 // Start the worker.
 window.onload = () => {
 document.worker.postMessage("");
 };
 </script>
  </head>
  <body>
    <div id="logDisplay"></div>
  </body>
</html>
```

The embedded worker is now nested into a new custom `document.worker` property.

It is also worth noting that you can also convert a function into a Blob, then generate an object URL from that blob. For example:

```js
function fn2workerURL(fn) {
  const blob = new Blob([`(${fn.toString()})()`], { type: "text/javascript" });
  return URL.createObjectURL(blob);
}
```

Further examples
----------------

This section provides further examples of how to use web workers.

### Performing computations in the background

Workers are mainly useful for allowing your code to perform processor-intensive calculations without blocking the user interface thread. In this example, a worker is used to calculate Fibonacci numbers.

#### The JavaScript code

The following JavaScript code is stored in the "fibonacci.js" file referenced by the HTML in the next section.

```js
self.onmessage = (event) => {
  const userNum = Number(event.data);
  self.postMessage(fibonacci(userNum));
};

function fibonacci(num) {
  let a = 1;
  let b = 0;
  while (num > 0) {
    [a, b] = [a + b, a];
    num--;
  }

  return b;
}
```

The worker sets the property `onmessage` to a function which will receive messages sent when the worker object's `postMessage()` is called. This performs the math and eventually returns the result back to the main thread.

#### The HTML code

```html
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="UTF-8" />
    <title>Fibonacci number generator</title>
    <style>
 body {
 width: 500px;
 }

 div,
 p {
 margin-bottom: 20px;
 }
 </style>
  </head>
  <body>
    <form>
      <div>
        <label for="number"
 >Enter a number that is a zero-based index position in the fibonacci
          sequence to see what number is in that position. For example, enter 6
          and you'll get a result of 8 — the fibonacci number at index position
          6 is 8.</label
 >
        <input type="number" id="number" />
      </div>
      <div>
        <input type="submit" />
      </div>
    </form>

    <p id="result"></p>

    <script>
 const form = document.querySelector("form");
 const input = document.querySelector('input[type="number"]');
 const result = document.querySelector("p#result");
 const worker = new Worker("fibonacci.js");

 worker.onmessage = (event) => {
 result.textContent = event.data;
 console.log(`Got: ${event.data}`);
 };

 worker.onerror = (error) => {
 console.log(`Worker error: ${error.message}`);
 throw error;
 };

 form.onsubmit = (e) => {
 e.preventDefault();
 worker.postMessage(input.value);
 input.value = "";
 };
 </script>
  </body>
</html>
```

The web page creates a `<p>` element with the ID `result`, which gets used to display the result, then spawns the worker. After spawning the worker, the `onmessage` handler is configured to display the results by setting the contents of the `<p>` element, and the `onerror` handler is set to log the error message to the devtools console.

Finally, a message is sent to the worker to start it.

Try this example live.

### Dividing tasks among multiple workers

As multicore computers become increasingly common, it's often useful to divide computationally complex tasks among multiple workers, which may then perform those tasks on multiple-processor cores.

Other types of workers
----------------------

In addition to dedicated and shared web workers, there are other types of workers available:

* ServiceWorkers essentially act as proxy servers that sit between web applications, and the browser and network (when available). They are intended to (amongst other things) enable the creation of effective offline experiences, intercepting network requests and taking appropriate action based on whether the network is available and updated assets reside on the server. They will also allow access to push notifications and background sync APIs.
* Audio Worklet provide the ability for direct scripted audio processing to be done in a worklet (a lightweight version of worker) context.
Debugging worker threads
------------------------

Most browsers enable you to debug web workers in their JavaScript debuggers in *exactly the same way* as debugging the main thread! For example, both Firefox and Chrome list JavaScript source files for both the main thread and active worker threads, and all of these files can be opened to set breakpoints and logpoints.

To learn how to debug web workers, see the documentation for each browser's JavaScript debugger:

* Chrome Sources panel
* Firefox JavaScript Debugger
Functions and interfaces available in workers
---------------------------------------------

You can use most standard JavaScript features inside a web worker, including:

* `Navigator`
* `fetch()`
* `Array`, `Date`, `Math`, and `String`
* `setTimeout()` and `setInterval()`

The main thing you *can't* do in a Worker is directly affect the parent page. This includes manipulating the DOM and using that page's objects. You have to do it indirectly, by sending a message back to the main script via `DedicatedWorkerGlobalScope.postMessage`, then doing the changes in event handler.

**Note:** You can test whether a method is available to workers using the site: https://worker-playground.glitch.me/. For example, if you enter EventSource into the site on Firefox 84 you'll see that this is not supported in service workers, but is in dedicated and shared workers.

**Note:** For a complete list of functions available to workers, see Functions and interfaces available to workers.

Specifications
--------------

| Specification |
| --- |
| HTML Standard # workers |

See also
--------

* `Worker` interface
* `SharedWorker` interface
* Functions available to workers
* `OffscreenCanvas` interface


Functions and classes available to Web Workers - Web APIs

Functions and classes available to Web Workers
==============================================

In addition to the standard JavaScript set of functions (such as `String`, `Array`, `Object`, `JSON`, etc.), there are a variety of functions available from the DOM to workers. This article provides a list of those.

Worker Contexts & Functions
---------------------------

**Workers run in a different global context than the current window!** While `Window` is not directly available to workers, many of the same methods are defined in a shared mixin (`WindowOrWorkerGlobalScope`), and made available to workers through their own `WorkerGlobalScope`-derived contexts:

* `DedicatedWorkerGlobalScope` for dedicated workers
* `SharedWorkerGlobalScope` for shared workers
* `ServiceWorkerGlobalScope` for service workers

Some of the functions (a subset) that are common to all workers and to the main thread (from `WindowOrWorkerGlobalScope`) are:

* `atob()`
* `btoa()`
* `clearInterval()`
* `clearTimeout()`
* `createImageBitmap()`
* `dump()`
Non-standard
* `fetch()`
* `queueMicrotask()`
* `reportError()`
* `setInterval()`
* `setTimeout()`
* `structuredClone()`
* `requestAnimationFrame()` (dedicated workers only)
* `cancelAnimationFrame()` (dedicated workers only)

The following functions are **only** available to workers:

* `WorkerGlobalScope.importScripts()` (all workers)
* `DedicatedWorkerGlobalScope.postMessage` (dedicated workers only)
Web APIs available in workers
-----------------------------

**Note:** If a listed API is supported by a platform in a particular version, then it can generally be assumed to be available in web workers. You can also test support for a particular object/function using the site: https://worker-playground.glitch.me/

The following Web APIs are available to workers:

* Background Fetch API
* Background Synchronization API
* Barcode Detection API
* Broadcast Channel API
* Canvas API
* Channel Messaging API
* Console API
* Compression Streams API
* CSS Font Loading API
* `CustomEvent`
* Encoding API (e.g. `TextEncoder`, `TextDecoder`)
* Fetch API
* File API
* File System API
* Idle Detection API
* IndexedDB API
* Media Capabilities API
* Media Source Extensions API (dedicated workers only)
* Network Information API
* Notifications API
* Payment Handler API
* Performance API
* Permissions API
* Prioritized Task Scheduling API
* Push API
* Server-sent events
* Service Worker API
* Streams API
* Trusted Types API
* URL API (e.g. `URL`)
* URL Pattern API
* User-Agent Client Hints API
* WebCodecs API
* Web Crypto API (e.g. `Crypto`)
* Web Locks API
* Web Serial API
* Web Periodic Background Synchronization API
* WebGPU API
* WebUSB API
* WebSockets API
* XMLHttpRequest API

Workers can also spawn other workers, so these APIs are also available:

* `Worker`
* `WorkerGlobalScope`
* `WorkerLocation`
* `WorkerNavigator`
See also
--------

* Using web workers
* `Worker`


Transferable objects - Web APIs

Transferable objects
====================

**Transferable objects** are objects that own resources that can be *transferred* from one context to another, ensuring that the resources are only available in one context at a time.
 Following a transfer, the original object is no longer usable; it no longer points to the transferred resource, and any attempt to read or write the object will throw an exception.

*Transferable objects* are commonly used to share resources that can only be safely exposed to a single JavaScript thread at a time.
 For example, an `ArrayBuffer` is a transferable object that owns a block of memory.
 When such a buffer is transferred between threads, the associated memory resource is detached from the original buffer and attached to the buffer object created in the new thread.
 The buffer object in the original thread is no longer usable because it no longer owns a memory resource.

 Transferring may also be used when creating deep copies of objects with `structuredClone()`.
 Following the cloning operation, the transferred resources are moved rather than copied to the cloned object.

 The mechanism used to transfer an object's resources depends on the object.
 For example, when an `ArrayBuffer` is transferred between threads, the memory resource that it points to is *literally* moved between contexts in a fast and efficient zero-copy operation.
 Other objects may be transferred by copying the associated resource and then deleting it from the old context.

 Not all objects are transferable.
 A list of transferable objects is provided below.

Transferring objects between threads
------------------------------------

 The code below demonstrates how transferring works when sending a message from a main thread to a web worker thread.
 The `Uint8Array` is copied (duplicated) in the worker while its buffer is transferred.
 After transfer any attempt to read or write `uInt8Array` from the main thread will throw, but you can still check the `byteLength` to confirm it is now zero.

```js
// Create an 8MB "file" and fill it. 8MB = 1024 \* 1024 \* 8 B
const uInt8Array = new Uint8Array(1024 \* 1024 \* 8).map((v, i) => i);
console.log(uInt8Array.byteLength); // 8388608

// Transfer the underlying buffer to a worker
worker.postMessage(uInt8Array, [uInt8Array.buffer]);
console.log(uInt8Array.byteLength); // 0
```

**Note:** Typed arrays like `Int32Array` and `Uint8Array`, are serializable, but not transferable.
 However their underlying buffer is an `ArrayBuffer`, which is a transferable object.
 We could have sent `uInt8Array.buffer` in the data parameter, but not `uInt8Array` in the transfer array.

### Transferring during a cloning operation

The code below shows a `structuredClone()` operation where the underlying buffer is copied from the original object to the clone.

```js
const original = new Uint8Array(1024);
const clone = structuredClone(original);
console.log(original.byteLength); // 1024
console.log(clone.byteLength); // 1024

original[0] = 1;
console.log(clone[0]); // 0

// Transferring the Uint8Array would throw an exception as it is not a transferable object
// const transferred = structuredClone(original, {transfer: [original]});

// We can transfer Uint8Array.buffer.
const transferred = structuredClone(original, { transfer: [original.buffer] });
console.log(transferred.byteLength); // 1024
console.log(transferred[0]); // 1

// After transferring Uint8Array.buffer cannot be used.
console.log(original.byteLength); // 0
```

Supported objects
-----------------

The items that various specifications indicate can be *transferred* are:

* `ArrayBuffer`
* `MessagePort`
* `ReadableStream`
* `WritableStream`
* `TransformStream`
* `WebTransportReceiveStream`
* `WebTransportSendStream`
* `AudioData`
* `ImageBitmap`
* `VideoFrame`
* `OffscreenCanvas`
* `RTCDataChannel`

 Browser support should be indicated in the respective object's compatibility information by the `transferable` subfeature (see `RTCDataChannel` for an example).
 At time of writing, not all transferable objects have been updated with this information.

**Note:** Transferable objects are marked up in Web IDL files with the attribute `[Transferable]`.

See also
--------

* Transferable Objects: Lightning Fast!
* Using Web Workers
* Transferable objects in the HTML specification
* `DedicatedWorkerGlobalScope.postMessage()`


The structured clone algorithm - Web APIs

The structured clone algorithm
==============================

 The **structured clone algorithm** copies complex JavaScript objects.
 It is used internally when invoking `structuredClone()`, to transfer data between Workers via `postMessage()`, storing objects with IndexedDB, or copying objects for other APIs.

It clones by recursing through the input object while maintaining a map of previously visited references, to avoid infinitely traversing cycles.

Things that don't work with structured clone
--------------------------------------------

* `Function` objects cannot be duplicated by the structured clone algorithm; attempting to throws a `DataCloneError` exception.
* Cloning DOM nodes likewise throws a `DataCloneError` exception.
* Certain object properties are not preserved:
    + The `lastIndex` property of `RegExp` objects is not preserved.
    + Property descriptors, setters, getters, and similar metadata-like features are not duplicated.
     For example, if an object is marked readonly with a property descriptor, it will be read/write in the duplicate, since that's the default.
    + The prototype chain is not walked or duplicated.
Supported types
---------------

### JavaScript types

* `Array`
* `ArrayBuffer`
* `Boolean`
* `DataView`
* `Date`
* `Error` types (but see Error types below).
* `Map`
* `Number`
* `Object` objects: but only plain objects (e.g. from object literals).
* Primitive types, except `symbol`.
* `RegExp`: but note that `lastIndex` is not preserved.
* `Set`
* `String`
* `TypedArray`

#### Error types

For `Error` types, the error name must be one of: `Error`, `EvalError`, `RangeError`, `ReferenceError`, `SyntaxError`, `TypeError`, `URIError` (or will be set to "Error").

Browsers must serialize the properties `name` and `message`, and are expected to serialize other "interesting" properties of the errors such as `stack`, `cause`, etc.

`AggregateError` support is expected to be added to the specification in whatwg/html#5749 (and is already supported in some browsers).

### Web/API types

* `AudioData`
* `Blob`
* `CropTarget`
* `CryptoKey`
* `DOMException`: browsers must serialize the properties `name` and `message`. Other attributes may also be serialized/cloned.
* `DOMMatrix`
* `DOMMatrixReadOnly`
* `DOMPoint`
* `DOMPointReadOnly`
* `DOMQuad`
* `DOMRect`
* `DOMRectReadOnly`
* `File`
* `FileList`
* `FileSystemDirectoryHandle`
* `FileSystemFileHandle`
* `FileSystemHandle`
* `GPUCompilationInfo`
* `GPUCompilationMessage`
* `ImageBitmap`
* `ImageData`
* `RTCCertificate`
* `VideoFrame`
See also
--------

* HTML Specification: Safe passing of structured data
* Transferable objects
* `structuredClone()`
* `window.postMessage()`
* Web Workers
* IndexedDB


Cache: delete() method - Web APIs

Cache: delete() method
======================

 The **`delete()`** method of the `Cache` interface finds the `Cache` entry whose key is the request, and if found, deletes the `Cache` entry and returns a `Promise` that resolves to `true`.
 If no `Cache` entry is found, it resolves to `false`.

Syntax
------

```js
delete(request)
delete(request, options)
```

### Parameters

`request`

 The `Request` you are looking to delete.
 This can be a `Request` object or a URL.

`options` Optional

 An object whose properties control how matching is done in the `delete` operation.
 The available options are:

`ignoreSearch`

 A boolean value that specifies whether the matching process should ignore the query string in the URL.
 If set to `true`, the `?value=bar` part of `http://foo.com/?value=bar` would be ignored when performing a match.
 It defaults to `false`.

`ignoreMethod`

 A boolean value that, when set to
 `true`, prevents matching operations from validating the
 `Request` `HTTP` method (normally only `GET`
 and `HEAD` are allowed.) It defaults to `false`.

`ignoreVary`

 A boolean value that, when set to
 `true,` tells the matching operation not to perform `VARY`
 header matching. In other words, if the URL matches you will get a match
 regardless of whether the `Response` object has a `VARY`
 header. It defaults to `false`.

`cacheName`

A string that represents a specific cache to search within. Note that this option is ignored by `Cache.delete()`.

### Return value

 a `Promise` that resolves to `true` if the cache entry is
 deleted, or `false` otherwise.

Examples
--------

```js
caches.open("v1").then((cache) => {
  cache.delete("/images/image.png").then((response) => {
    someUIUpdateFunction();
  });
});
```

Specifications
--------------

| Specification |
| --- |
| Service Workers # cache-delete |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Using Service Workers
* `Cache`
* `caches`


Cache: put() method - Web APIs

Cache: put() method
===================

 The **`put()`** method of the
 `Cache` interface allows key/value pairs to be added to the current
 `Cache` object.

 Often, you will just want to `fetch()`
 one or more requests, then add the result straight to your cache. In such cases you are
 better off using
 `Cache.add()`/`Cache.addAll()`, as
 they are shorthand functions for one or more of these operations.

```js
fetch(url).then((response) => {
  if (!response.ok) {
    throw new TypeError("Bad response status");
  }
  return cache.put(url, response);
});
```

**Note:** `put()` will overwrite any key/value pair
 previously stored in the cache that matches the request.

**Note:** `Cache.add`/`Cache.addAll` do not
 cache responses with `Response.status` values that are not in the 200
 range, whereas `Cache.put` lets you store any request/response pair. As a
 result, `Cache.add`/`Cache.addAll` can't be used to store
 opaque responses, whereas `Cache.put` can.

Syntax
------

```js
put(request, response)
```

### Parameters

`request`

The `Request` object or URL that you want to add to the cache.

`response`

The `Response` you want to match up to the request.

### Return value

A `Promise` that resolves with `undefined`.

### Exceptions

`TypeError`

Returned if the URL scheme is not `http` or `https`.

Examples
--------

 This example is from the MDN simple-service-worker example (see simple-service-worker running live).
 Here we wait for a `FetchEvent` to fire. We construct a custom response
 like so:

1. Check whether a match for the request is found in the `CacheStorage`
 using `CacheStorage.match()`. If so, serve that.
2. If not, open the `v1` cache using `open()`, put the default
 network request in the cache using `Cache.put()` and return a
 clone of the default network request using `return response.clone()`. Clone
 is needed because `put()` consumes the response body.
3. If this fails (e.g., because the network is down), return a fallback response.

```js
let response;
const cachedResponse = caches
  .match(event.request)
  .then((r) => (r !== undefined ? r : fetch(event.request)))
  .then((r) => {
    response = r;
    caches.open("v1").then((cache) => {
      cache.put(event.request, response);
    });
    return response.clone();
  })
  .catch(() => caches.match("/gallery/myLittleVader.jpg"));
```

Specifications
--------------

| Specification |
| --- |
| Service Workers # cache-put |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Using Service Workers
* `Cache`
* `caches`


Cache: keys() method - Web APIs

Cache: keys() method
====================

 The **`keys()`** method of the `Cache` interface returns a
 `Promise` that resolves to an array of `Request` objects
 representing the keys of the `Cache`.

The requests are returned in the same order that they were inserted.

**Note:** Requests with duplicate URLs but different headers can be
 returned if their responses have the `VARY` header set on them.

Syntax
------

```js
keys()
keys(request)
keys(request, options)
```

### Parameters

`request` Optional

 The `Request` want to return, if a specific key is desired. This can be
 a `Request` object or a URL.

`options` Optional

 An object whose properties control how matching is done in the `keys`
 operation. The available options are:

`ignoreSearch`

 A boolean value that specifies whether the
 matching process should ignore the query string in the URL. If set to
 `true`, the `?value=bar` part of
 `http://foo.com/?value=bar` would be ignored when performing a match.
 It defaults to `false`.

`ignoreMethod`

 A boolean value that, when set to
 `true`, prevents matching operations from validating the
 `Request` `HTTP` method (normally only `GET`
 and `HEAD` are allowed.) It defaults to `false`.

`ignoreVary`

 A boolean value that, when set to
 `true,` tells the matching operation not to perform `VARY`
 header matching. In other words, if the URL matches you will get a match
 regardless of whether the `Response` object has a `VARY`
 header. It defaults to `false`.

`cacheName`

 A string that represents a specific
 cache to search within. Note that this option is ignored by
 `Cache.keys()`.

### Return value

 A `Promise` that resolves to an array of `Request`
 objects.

Examples
--------

```js
caches.open("v1").then((cache) => {
  cache.keys().then((keys) => {
    keys.forEach((request, index, array) => {
      cache.delete(request);
    });
  });
});
```

Specifications
--------------

| Specification |
| --- |
| Service Workers # cache-keys |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Using Service Workers
* `Cache`
* `caches`


Cache: match() method - Web APIs

Cache: match() method
=====================

 The **`match()`** method of the `Cache` interface returns a `Promise` that resolves to the `Response` associated with the first matching request in the `Cache` object.
 If no match is found, the `Promise` resolves to `undefined`.

Syntax
------

```js
match(request)
match(request, options)
```

### Parameters

`request`

 The `Request` for which you are attempting to find responses in the
 `Cache`. This can be a `Request` object or a URL string.

`options` Optional

 An object that sets options for the `match` operation.
 The available options are:

`ignoreSearch`

 A boolean value that specifies whether to
 ignore the query string in the URL. For example, if set to
 `true` the `?value=bar` part of
 `http://foo.com/?value=bar` would be ignored when performing a match.
 It defaults to `false`.

`ignoreMethod`

 A boolean value that, when set to
 `true`, prevents matching operations from validating the
 `Request` `http` method (normally only `GET`
 and `HEAD` are allowed.) It defaults to `false`.

`ignoreVary`

 A boolean value that when set to
 `true` tells the matching operation not to perform `VARY`
 header matching — i.e. if the URL matches you will get a match regardless of
 whether the `Response` object has a `VARY` header. It
 defaults to `false`.

### Return value

 A `Promise` that resolves to the first `Response` that matches
 the request or to `undefined` if no match is found.

**Note:** `Cache.match()` is basically identical to
 `Cache.matchAll()`, except that rather than resolving with an array of
 all matching responses, it resolves with the first matching response only (that is,
 `response[0]`).

Examples
--------

 This example is taken from the custom offline page example (live demo). It uses a cache to supply selected data when a request fails. A
 `catch()` clause is triggered when the call to `fetch()` throws an
 exception. Inside the `catch()` clause, `match()` is used to
 return the correct response.

 In this example, only HTML documents retrieved with the GET HTTP verb will be
 cached. If our `if ()` condition is false, then this fetch handler won't
 intercept the request. If there are any other fetch handlers registered, they will get a
 chance to call `event.respondWith()`. If no fetch handlers call
 `event.respondWith()`, the request will be handled by the browser as if there
 were no service worker involvement. If `fetch()` returns a valid HTTP
 response with an response code in the 4xx or 5xx range, the `catch()` will
 NOT be called.

```js
self.addEventListener("fetch", (event) => {
  // We only want to call event.respondWith() if this is a GET request for an HTML document.
  if (
    event.request.method === "GET" &&
    event.request.headers.get("accept").includes("text/html")
  ) {
    console.log("Handling fetch event for", event.request.url);
    event.respondWith(
      fetch(event.request).catch((e) => {
        console.error("Fetch failed; returning offline page instead.", e);
        return caches
          .open(OFFLINE\_CACHE)
          .then((cache) => cache.match(OFFLINE\_URL));
      }),
    );
  }
});
```

Specifications
--------------

| Specification |
| --- |
| Service Workers # cache-match |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Using Service Workers
* `Cache`
* `caches`


Cache: add() method - Web APIs

Cache: add() method
===================

The **`add()`** method of the `Cache` interface takes a URL, retrieves it, and adds the resulting response object to the given cache.

The `add()` method is functionally equivalent to the following:

```js
fetch(url).then((response) => {
  if (!response.ok) {
    throw new TypeError("bad response status");
  }
  return cache.add(url);
});
```

For more complex operations, you'll need to use `Cache.put()` directly.

**Note:** `add()` will overwrite any key/value pair previously stored in the cache that matches the request.

Syntax
------

```js
add(request)
```

### Parameters

`request`

A request for the resource you want to add to the cache. This can be a `Request` object or a URL.

This parameter is used as a parameter to the `Request()` constructor, so URLs follow the same rules as for that constructor. In particular, URLs may be relative to the base URL, which is the document's `baseURI` in a window context, or `WorkerGlobalScope.location` in a worker context.

### Return value

A `Promise` that resolves with `undefined`.

### Exceptions

`TypeError`

The URL scheme is not `http` or `https`.

The Response status is not in the 200 range (i.e., not a successful response.) This occurs if the request does not return successfully, but also if the request is a *cross-origin no-cors* request (in which case the reported status is always 0.)

Examples
--------

This code block waits for an `InstallEvent` to fire, then calls `waitUntil()` to handle the install process for the app. This consists of calling `CacheStorage.open` to create a new cache, then using `Cache.add` to add an asset to it.

```js
this.addEventListener("install", (event) => {
  event.waitUntil(caches.open("v1").then((cache) => cache.add("/index.html")));
});
```

Specifications
--------------

| Specification |
| --- |
| Service Workers # cache-add |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Using Service Workers
* `Cache`
* `caches`


Cache: addAll() method - Web APIs

Cache: addAll() method
======================

The **`addAll()`** method of the `Cache` interface takes an array of URLs, retrieves them, and adds the resulting response objects to the given cache. The request objects created during retrieval become keys to the stored response operations.

**Note:** `addAll()` will overwrite any key/value pairs
 previously stored in the cache that match the request, but will fail if a
 resulting `put()` operation would overwrite a previous cache entry stored by the same `addAll()` method.

Syntax
------

```js
addAll(requests)
```

### Parameters

`requests`

An array of requests for the resources you want to add to the cache. These can be `Request` objects or URLs.

These requests are used as parameters to the `Request()` constructor, so URLs follow the same rules as for that constructor. In particular, URLs may be relative to the base URL, which is the document's `baseURI` in a window context, or `WorkerGlobalScope.location` in a worker context.

### Return value

A `Promise` that resolves with `undefined`.

### Exceptions

`TypeError`

The URL scheme is not `http` or `https`.

The Response status is not in the 200 range (i.e., not a successful response.) This occurs if the request does not return successfully, but also if the request is a *cross-origin no-cors* request (in which case the reported status is always 0.)

Examples
--------

 This code block waits for an `InstallEvent` to fire, then runs
 `waitUntil()` to handle the install process for
 the app. This consists of calling `CacheStorage.open` to create a new
 cache, then using `addAll()` to add a series of assets to it.

```js
this.addEventListener("install", (event) => {
  event.waitUntil(
    caches
      .open("v1")
      .then((cache) =>
        cache.addAll([
          "/",
          "/index.html",
          "/style.css",
          "/app.js",
          "/image-list.js",
          "/star-wars-logo.jpg",
          "/gallery/",
          "/gallery/bountyHunters.jpg",
          "/gallery/myLittleVader.jpg",
          "/gallery/snowTroopers.jpg",
        ]),
      ),
  );
});
```

Specifications
--------------

| Specification |
| --- |
| Service Workers # cache-addAll |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Using Service Workers
* `Cache`
* `caches`


Cache: matchAll() method - Web APIs

Cache: matchAll() method
========================

 The **`matchAll()`** method of the `Cache`
 interface returns a `Promise` that resolves to an array of all matching
 responses in the `Cache` object.

Syntax
------

```js
matchAll()
matchAll(request)
matchAll(request, options)
```

### Parameters

`request` Optional

 The `Request` for which you are attempting to find responses in the
 `Cache`. This can be a `Request` object or a URL. If this
 argument is omitted, you will get a copy of all responses in this cache.

`options` Optional

 An options object allowing you to set specific control options for the matching
 performed. The available options are:

`ignoreSearch`

 A boolean value that specifies whether the
 matching process should ignore the query string in the URL. If set to
 `true`, the `?value=bar` part of
 `http://foo.com/?value=bar` would be ignored when performing a match.
 It defaults to `false`.

`ignoreMethod`

 A boolean value that, when set to
 `true`, prevents matching operations from validating the
 `Request` `http` method (normally only `GET`
 and `HEAD` are allowed.) It defaults to `false`.

`ignoreVary`

 A boolean value that when set to
 `true` tells the matching operation not to perform `VARY`
 header matching — i.e. if the URL matches you will get a match regardless of the
 `Response` object having a `VARY` header or not. It
 defaults to `false`.

### Return value

 A `Promise` that resolves to an array of all matching responses in the
 `Cache` object.

**Note:** `Cache.match()` is basically identical to
 `Cache.matchAll()`, except that rather than resolving with an array of all
 matching responses, it resolves with the first matching response only (that is,
 `response[0]`).

Examples
--------

The following example retrieves all responses in the `v1` cache matching the URL `/`, even including potential query parameters. By using `{ ignoreSearch: true }`, using `matchAll` would retrieve `/` as well as `/?value=bar`.

It then logs the number of matching responses.

```js
caches.open("v1").then((cache) => {
  cache.matchAll("/", { ignoreSearch: true }).then((responses) => {
    console.log(`Found ${responses.length} matching responses`);
  });
});
```

Specifications
--------------

| Specification |
| --- |
| Service Workers # cache-matchall |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Using Service Workers
* `Cache`
* `caches`


SerialPort: open() method - Web APIs

SerialPort: open() method
=========================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`open()`** method of the `SerialPort` interface returns a `Promise` that resolves when the port is opened. By default the port is opened with 8 data bits, 1 stop bit and no parity checking. The `baudRate` parameter is required.

Syntax
------

```js
open(options)
```

### Parameters

`options`

An object with any of the following values:

`baudRate`

A positive, non-zero value indicating the baud rate at which serial communication should be established.

`bufferSize` Optional

An unsigned long integer indicating the size of the read and write buffers that are to be established. If not passed, defaults to 255.

`dataBits` Optional

An integer value of 7 or 8 indicating the number of data bits per frame. If not passed, defaults to 8.

`flowControl` Optional

The flow control type, either `"none"` or `"hardware"`. The default value is `"none"`.

`parity` Optional

The parity mode, either `"none"`, `"even"`, or `"odd"`. The default value is `"none"`.

`stopBits` Optional

An integer value of 1 or 2 indicating the number of stop bits at the end of the frame. If not passed, defaults to 1.

### Return value

A `Promise`.

### Exceptions

`InvalidStateError` `DOMException`

Returned if the port is already open.

`NetworkError` `DOMException`

Returned if the attempt to open the port failed.

Examples
--------

Before communicating on a serial port it must be opened. Opening the port allows the site to specify the necessary parameters that control how data is transmitted and received. Developers should check the documentation for the device they are connecting to for the appropriate parameters.

```js
await port.open({ baudRate: 9600 /\* pick your baud rate \*/ });
```

Specifications
--------------

| Specification |
| --- |
| Web Serial API # dom-serialport-open |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


SerialPort: getInfo() method - Web APIs

SerialPort: getInfo() method
============================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`getInfo()`** method of the `SerialPort` interface returns an object whose properties are the vendor ID and product ID of the device.

Syntax
------

```js
getInfo()
```

### Parameters

None.

### Return value

An object containing the following values.

`usbVendorId`

If the port is part of a USB device, an unsigned short integer that identifies a USB device vendor, otherwise `undefined`.

`usbProductId`

If the port is part of a USB device, an unsigned short integer that identifies a USB device, otherwise `undefined`.

Specifications
--------------

| Specification |
| --- |
| Web Serial API # dom-serialport-getinfo |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


SerialPort: writable property - Web APIs

SerialPort: writable property
=============================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`writable`** read-only property of the `SerialPort` interface returns a `WritableStream` for sending data to the device connected to the port. Chunks written to this stream must be instances of `ArrayBuffer`, `TypedArray`, or `DataView`. This property is non-null as long as the port is open and has not encountered a fatal error.

Value
-----

A `WritableStream`

Examples
--------

The following example shows how to write a string to a port. A `TextEncoder` converts the string to a `Uint8Array` before transmission.

```js
const encoder = new TextEncoder();
const writer = port.writable.getWriter();
await writer.write(encoder.encode("PING"));
writer.releaseLock();
```

Specifications
--------------

| Specification |
| --- |
| Web Serial API # dom-serialport-writable |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


SerialPort: close() method - Web APIs

SerialPort: close() method
==========================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`SerialPort.close()`** method of the `SerialPort` interface returns a `Promise` that resolves when the port closes.

Syntax
------

```js
close()
```

### Parameters

None.

### Return value

A `Promise`.

Specifications
--------------

| Specification |
| --- |
| Web Serial API # dom-serialport-close |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


SerialPort: connect event - Web APIs

SerialPort: connect event
=========================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`connect`** event of the `SerialPort` interface is fired when a port has connected to the device. This event is only fired for ports associated with removable devices such as those connected via USB.

This event bubbles to the instance of `Serial` that returned this interface.

Syntax
------

Use the event name in methods like `addEventListener()`, or set an event handler property.

```js
addEventListener("connect", (event) => {});

onconnect = (event) => {};
```

Event type
----------

A generic `Event`.

Bubbling
--------

This event bubbles to `Serial`. The `event.target` property refers to the `SerialPort` object that bubbles up.

For more information, see Event bubbling.

Examples
--------

### Notify when a specific port connects

The `Serial.requestPort()` method returns a `Promise` that resolves with a `SerialPort` chosen by the user.

```js
// Prompt user to choose a serial port
const port = await navigator.serial.requestPort();

port.addEventListener("connect", (event) => {
  // notify that the chosen port is connected
});
```

### Listening for any newly-connected ports

The `connect` event bubbles up to the `Serial` object where you can listen for any newly-connected ports.

```js
navigator.serial.addEventListener("connect", (event) => {
  // notify that a new port is available
  // use `event.target` to refer to the newly-added port
});
```

Specifications
--------------

| Specification |
| --- |
| Web Serial API # dfn-connect |
| Web Serial API # dom-serialport-onconnect |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `disconnect` event


SerialPort: readable property - Web APIs

SerialPort: readable property
=============================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`readable`** read-only property of the `SerialPort` interface returns a `ReadableStream` for receiving data from the device connected to the port. Chunks read from this stream are instances of `Uint8Array`. This property is non-null as long as the port is open and has not encountered a fatal error.

Value
-----

A `ReadableStream`.

Examples
--------

The following example shows how to read data from a port. The outer loop handles non-fatal errors, creating a new reader until a fatal error is encountered and `readable` becomes `null`.

```js
while (port.readable) {
  const reader = port.readable.getReader();
  try {
    while (true) {
      const { value, done } = await reader.read();
      if (done) {
        // |reader| has been canceled.
        break;
      }
      // Do something with |value|…
    }
  } catch (error) {
    // Handle |error|…
  } finally {
    reader.releaseLock();
  }
}
```

Specifications
--------------

| Specification |
| --- |
| Web Serial API # dom-serialport-readable |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


SerialPort: forget() method - Web APIs

SerialPort: forget() method
===========================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`SerialPort.forget()`** method of the `SerialPort` interface returns a `Promise` that resolves when the serial port is closed and is forgotten.

Syntax
------

```js
forget()
```

### Parameters

None.

### Return value

A `Promise` that resolves with `undefined` once the connection is closed, the device is forgotten, and the permission is reset.

Specifications
--------------

| Specification |
| --- |
| Web Serial API # dom-serialport-forget |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


SerialPort: setSignals() method - Web APIs

SerialPort: setSignals() method
===============================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`setSignals()`** method of the `SerialPort` interface sets control signals on the port and returns a `Promise` that resolves when they are set.

Syntax
------

```js
setSignals()
setSignals(options)
```

### Parameters

`options` Optional

An object with any of the following values:

`dataTerminalReady`

A boolean indicating whether to invoke the operating system to either assert (if true) or de-assert (if false) the "data terminal ready" or "DTR" signal on the serial port.

`requestToSend`

A boolean indicating whether to invoke the operating system to either assert (if true) or de-assert (if false) the "request to send" or "RTS" signal on the serial port.

`break`

A boolean indicating whether to invoke the operating system to either assert (if true) or de-assert (if false) the "break" signal on the serial port.

### Return value

A `Promise`.

### Exceptions

`InvalidStateError` `DOMException`

Returned if the port is not open. Call `SerialPort.open()` to avoid this error.

`NetworkError` `DOMException`

Returned if the signals on the device could not be set.

Specifications
--------------

| Specification |
| --- |
| Web Serial API # dom-serialport-setsignals |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


SerialPort: disconnect event - Web APIs

SerialPort: disconnect event
============================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`disconnect`** event of the `SerialPort` interface is fired when the port has disconnected from the device. This event is only fired for ports associated with removable devices such as those connected via USB.

This event bubbles to the instance of `Serial` that returned this interface.

Syntax
------

Use the event name in methods like `addEventListener()`, or set an event handler property.

```js
addEventListener("disconnect", (event) => {});

ondisconnect = (event) => {};
```

Event type
----------

A generic `Event`.

Bubbling
--------

This event bubbles to `Serial`. The `event.target` property refers to the `SerialPort` object that bubbles up.

For more information, see Event bubbling.

Examples
--------

### Notify when a specific port disconnects

Here the event listener is installed on a specific `SerialPort` object.

```js
port.addEventListener("disconnect", (event) => {
  // notify that the port has become unavailable
});
```

### Listening for any ports that become unavailable

The `disconnect` event bubbles up to the `Serial` object where you can listen for any ports that become unavailable.

```js
navigator.serial.addEventListener("disconnect", (event) => {
  // notify that a port has become unavailable
  // use `event.target` to refer to the unavailable port
});
```

Specifications
--------------

| Specification |
| --- |
| Web Serial API # dfn-disconnect |
| Web Serial API # dom-serialport-ondisconnect |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `connect` event


SerialPort: getSignals() method - Web APIs

SerialPort: getSignals() method
===============================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`SerialPort.getSignals()`** method of the `SerialPort` interface returns a `Promise` that resolves with an object containing the current state of the port's control signals.

Syntax
------

```js
getSignals()
```

### Parameters

None.

### Return value

Returns a `Promise` that resolves with an object containing the following members:

`clearToSend`

A boolean indicating to the other end of a serial connection that is clear to send data.

`dataCarrierDetect`

A boolean that toggles the control signal needed to communicate over a serial connection.

`dataSetReady`

A boolean indicating whether the device is ready to send and receive data.

`ringIndicator`

A boolean indicating whether a ring signal should be sent down the serial connection.

### Exceptions

`InvalidStateError` `DOMException`

Returned if the port is not open. Call `SerialPort.open()` to avoid this error.

`NetworkError` `DOMException`

Returned if the signals on the device could not be read.

Specifications
--------------

| Specification |
| --- |
| Web Serial API # dom-serialport-getsignals |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


ContactsManager: select() method - Web APIs

ContactsManager: select() method
================================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

 The **`select()`** method of the
 `ContactsManager` interface returns a `Promise` which, when
 resolved, presents the user with a contact picker which allows them to select contact(s)
 they wish to share. This method requires a user gesture for the `Promise` to
 resolve.

Syntax
------

```js
select(properties)
select(properties, options)
```

### Parameters

`properties`

 An array of `strings` defining what information to retrieve
 from a contact. Allowed values are as follows:

* `'name'`: The contact's name.
* `'tel'`: The telephone number(s) of the contact.
* `'email'`: The email address of the contact.
* `'address'`: The contact's postal address.
* `'icon'`: The avatar of the contact.

`options` Optional

Options are as follows:

`multiple`

A Boolean that allows multiple contacts to be selected. The default is `false`.

### Return value

Returns a `Promise` that resolves with an array of objects containing contact information. Each object represents a single contact may contain the following properties:

`address`

An `Array` of `ContactAddress` objects, each containing specifics of a unique physical address.

`email`

An array of strings containing email addresses.

`icon`

An array of `Blob` objects containing images of an individual.

`name`

An array strings, each containing a unique name of an individual.

`tel`

An array strings, each containing a unique phone number of an individual.

### Exceptions

`InvalidStateError` `DOMException`

Returned if the browsing context is not top-level, if the contact picker shows a flag that denotes an already existing contact picker since only one picker can exist at any time, or if launching a contact picker failed.

`SecurityError` `DOMException`

Returned if the method is not triggered by user activation.

`TypeError`

 Returned if `properties` is empty, or if any of the specified properties are not
 supported.

Security
--------

Transient activation is required. The user has to interact with the page or a UI element in order for this feature to work.

Examples
--------

### Basic Example

 The following example sets an array of properties to be retrieved for each contact, as
 well as setting an options object to allow for multiple contacts to be selected.

 An asynchronous function is then defined which uses the `select()` method to
 present the user with a contact picker interface and handle the chosen results.
 `handleResults()` is a developer defined function.

```js
const props = ["name", "email", "tel", "address", "icon"];
const opts = { multiple: true };

async function getContacts() {
  try {
    const contacts = await navigator.contacts.select(props, opts);
    handleResults(contacts);
  } catch (ex) {
    // Handle any errors here.
  }
}
```

### Select Using Only Supported Properties

The following example uses `getProperties()` to ensure that only supported properties are passed. Otherwise, `select()` might throw a `TypeError`. `handleResults()` is a developer defined function.

```js
const supportedProperties = await navigator.contacts.getProperties();

async function getContacts() {
  try {
    const contacts = await navigator.contacts.select(supportedProperties);
    handleResults(contacts);
  } catch (ex) {
    // Handle any errors here.
  }
}
```

Specifications
--------------

| Specification |
| --- |
| Contact Picker API # contacts-manager-select |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


ContactsManager: getProperties() method - Web APIs

ContactsManager: getProperties() method
=======================================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

 The **`getProperties()`** method of the
 `ContactsManager` interface returns a `Promise` which resolves
 with an `Array` of `strings` indicating which contact
 properties are available.

Syntax
------

```js
getProperties()
```

### Parameters

This method receives no parameters.

### Return value

Returns a `Promise` that resolves with an `Array` of `strings` naming the contact properties that can be returned by the current system.

Properties can include the following:

* `'name'`: The contact's name.
* `'tel'`: The telephone number(s) of the contact.
* `'email'`: The email address of the contact.
* `'address'`: The contact's postal address.
* `'icon'`: The avatar of the contact.
### Exceptions

No exceptions are thrown.

Examples
--------

### Verify Property Support

 The following asynchronous function uses the `getProperties()` method to check
 whether the current system supports the `icon` property.

```js
async function checkProperties() {
  const supportedProperties = await navigator.contacts.getProperties();
  if (!supportedProperties.includes("icon")) {
    console.log("Your system does not support getting icons.");
  }
}
```

### Select Using Only Supported Properties

The following example is similar to one for the `select()` method. Instead of hard-coding the properties passed to `select()`, it uses `getProperties()` to ensure that only supported properties are passed. Otherwise, `select()` might throw a `TypeError`. `handleResults()` is a developer defined function.

```js
const supportedProperties = await navigator.contacts.getProperties();

async function getContacts() {
  try {
    const contacts = await navigator.contacts.select(supportedProperties);
    handleResults(contacts);
  } catch (ex) {
    // Handle any errors here.
  }
}
```

Specifications
--------------

| Specification |
| --- |
| Contact Picker API # contacts-manager-getproperties |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


MutationObserver: observe() method - Web APIs

MutationObserver: observe() method
==================================

 The `MutationObserver` method **`observe()`** configures the `MutationObserver`
 callback to begin receiving notifications of changes to the DOM that match the given options.

Depending on the configuration, the observer may watch a single `Node` in the DOM tree, or that node and some or all of its descendant nodes.

To stop the `MutationObserver` (so that none of its callbacks will be triggered any longer), call `MutationObserver.disconnect()`.

Syntax
------

```js
observe(target, options)
```

### Parameters

`target`

 A DOM `Node` (which may be an `Element`) within the DOM
 tree to watch for changes, or to be the root of a subtree of nodes to be watched.

`options`

 An object providing options that describe which DOM mutations should be reported to `mutationObserver`'s `callback`.
 At a minimum, one of `childList`, `attributes`, and/or `characterData` must be `true` when you call `observe()`.
 Otherwise, a `TypeError` exception will be thrown.

Options are as follows:

`subtree` Optional

 Set to `true` to extend monitoring to the entire subtree of nodes rooted at `target`.
 All of the other properties are then extended to all of the nodes in the subtree instead of applying solely to the `target` node. The default value is `false`.

`childList` Optional

 Set to `true` to monitor the target node (and, if `subtree` is `true`, its descendants) for the addition of new child nodes or removal of existing child nodes.
 The default value is `false`.

`attributes` Optional

Set to `true` to watch for changes to the value of attributes on the node or nodes being monitored. The default value is `true` if either of `attributeFilter` or `attributeOldValue` is specified, otherwise the default value is `false`.

`attributeFilter` Optional

 An array of specific attribute names to be monitored.
 If this property isn't included, changes to all attributes cause mutation notifications.

`attributeOldValue` Optional

 Set to `true` to record the previous value of any attribute that changes when monitoring the node or nodes for attribute changes;
 See Monitoring attribute values for an example of watching for attribute changes and recording values.
 The default value is `false`.

`characterData` Optional

 Set to `true` to monitor the specified target node (and, if `subtree` is `true`, its descendants) for changes to the character data contained within the node or nodes.
 The default value is `true` if `characterDataOldValue` is specified, otherwise the default value is `false`.

`characterDataOldValue` Optional

 Set to `true` to record the previous value of a node's text whenever the text changes on nodes being monitored.
 The default value is `false`.

### Return value

None (`undefined`).

### Exceptions

`TypeError`

Thrown in any of the following circumstances:

* The `options` are configured such that nothing will actually be monitored.
 (For example, if `childList`, `attributes`, and `characterData` are all `false`.)
* The value of `options.attributes` is `false` (indicating that attribute changes are not to be monitored), but `attributeOldValue` is `true` and/or
 `attributeFilter` is present.
* The `characterDataOldValue` option is `true` but `characterData` is `false` (indicating that character changes are not to be monitored).

Usage notes
-----------

### Reusing MutationObservers

 You can call `observe()` multiple times on the same
 `MutationObserver` to watch for changes to different parts of the DOM tree
 and/or different types of changes. There are some caveats to note:

* If you call `observe()` on a node that's already being observed by the same `MutationObserver`, all existing observers are automatically removed from all targets being observed before the new observer is activated.
* If the same `MutationObserver` is not already in use on the target, then the existing observers are left alone and the new one is added.
### Observation follows nodes when disconnected

 Mutation observers are intended to let you be able to watch the desired set of nodes
 over time, even if the direct connections between those nodes are severed. If you begin
 watching a subtree of nodes, and a portion of that subtree is detached and moved
 elsewhere in the DOM, you continue to watch the detached segment of nodes, receiving the
 same callbacks as before the nodes were detached from the original subtree.

 In other words, until you've been notified that nodes are being split off from your monitored subtree, you'll get notifications of changes to that split-off subtree and its nodes.
 This prevents you from missing changes that occur after the connection is severed
 and before you have a chance to specifically begin monitoring the moved node or subtree for changes.

 Theoretically, this means that if you keep track of the `MutationRecord` objects describing the changes that occur, you should be able to "undo" the changes,
 rewinding the DOM back to its initial state.

Examples
--------

### Basic usage

 In this example, we demonstrate how to call the method **`observe()`** on an instance of `MutationObserver`, once it has been set up, passing it a target element
 and an `options` object.

```js
// create a new instance of `MutationObserver` named `observer`,
// passing it a callback function
const observer = new MutationObserver(() => {
  console.log("callback that runs when observer is triggered");
});

// call `observe()`, passing it the element to observe, and the options object
observer.observe(document.querySelector("#element-to-observe"), {
  subtree: true,
  childList: true,
});
```

### Using `attributeFilter`

 In this example, a Mutation Observer is set up to watch for changes to the
 `status` and `username` attributes in any elements contained
 within a subtree that displays the names of users in a chat room. This lets the code,
 for example, reflect changes to users' nicknames, or to mark them as away from keyboard
 (AFK) or offline.

```js
function callback(mutationList) {
  mutationList.forEach((mutation) => {
    switch (mutation.type) {
      case "attributes":
        switch (mutation.attributeName) {
          case "status":
            userStatusChanged(mutation.target.username, mutation.target.status);
            break;
          case "username":
            usernameChanged(mutation.oldValue, mutation.target.username);
            break;
        }
        break;
    }
  });
}

const userListElement = document.querySelector("#userlist");

const observer = new MutationObserver(callback);
observer.observe(userListElement, {
  attributeFilter: ["status", "username"],
  attributeOldValue: true,
  subtree: true,
});
```

### Monitoring attribute values

In this example we observe an element for attribute value changes, and add a button which toggles the element's `dir` attribute between `"ltr"` and `"rtl"`. Inside the observer's callback, we log the old value of the attribute.

#### HTML

```html
<button id="toggle">Toggle direction</button><br />
<div id="container">
  <input type="text" id="rhubarb" dir="ltr" value="Tofu" />
</div>
<pre id="output"></pre>
```

#### CSS

```css
body {
  background-color: paleturquoise;
}

button,
input,
pre {
  margin: 0.5rem;
}
```

#### JavaScript

```js
const toggle = document.querySelector("#toggle");
const rhubarb = document.querySelector("#rhubarb");
const observerTarget = document.querySelector("#container");
const output = document.querySelector("#output");

toggle.addEventListener("click", () => {
  rhubarb.dir = rhubarb.dir === "ltr" ? "rtl" : "ltr";
});

const config = {
  subtree: true,
  attributeOldValue: true,
};

const callback = (mutationList) => {
  for (const mutation of mutationList) {
    if (mutation.type === "attributes") {
      output.textContent = `The ${mutation.attributeName} attribute was modified from "${mutation.oldValue}".`;
    }
  }
};

const observer = new MutationObserver(callback);
observer.observe(observerTarget, config);
```

#### Result

Specifications
--------------

| Specification |
| --- |
| DOM Standard # ref-for-dom-mutationobserver-observe② |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


MutationObserver: takeRecords() method - Web APIs

MutationObserver: takeRecords() method
======================================

 The `MutationObserver` method
 **`takeRecords()`** returns a list of all matching DOM changes
 that have been detected but not yet processed by the observer's callback function,
 leaving the mutation queue empty.

 The most common use case for this is to
 immediately fetch all pending mutation records immediately prior to disconnecting the
 observer, so that any pending mutations can be processed when shutting down the
 observer.

Syntax
------

```js
takeRecords()
```

### Parameters

None.

### Return value

 An array of `MutationRecord` objects, each describing one change applied to
 the observed portion of the document's DOM tree.

**Note:** The queue of mutations which have occurred, but not been
 delivered to the observer's callback is left empty after calling
 `takeRecords()`.

Examples
--------

 In this example, we demonstrate how to handle any undelivered
 `MutationRecord`s by calling `takeRecords()` just before
 disconnecting the observer.

```js
const targetNode = document.querySelector("#someElement");
const observerOptions = {
  childList: true,
  attributes: true,
};

const observer = new MutationObserver(callback);
observer.observe(targetNode, observerOptions);

/\* later, when it's time to stop observing… \*/

/\* handle any still-pending mutations \*/

let mutations = observer.takeRecords();

observer.disconnect();

if (mutations.length > 0) {
  callback(mutations);
}
```

 The code in lines 12–17 fetches any unprocessed mutation records, then invokes the
 callback with the records so that they can be processed. This is done immediately prior
 to calling `disconnect()` to stop observing
 the DOM.

Specifications
--------------

| Specification |
| --- |
| DOM Standard # ref-for-dom-mutationobserver-takerecords① |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


MutationObserver: MutationObserver() constructor - Web APIs

MutationObserver: MutationObserver() constructor
================================================

 The DOM **`MutationObserver()`**
 constructor — part of the `MutationObserver` interface — creates and
 returns a new observer which invokes a specified callback when DOM events
 occur.

 DOM observation does not begin immediately; the
 `observe()` method must be called first to
 establish which portion of the DOM to watch and what kinds of changes to watch for.

Syntax
------

```js
new MutationObserver(callback)
```

### Parameters

`callback`

 A function which will be called on each DOM change that qualifies given the
 observed node or subtree and options.

The `callback` function takes as input two parameters:

1. An array of `MutationRecord` objects, describing each change that
 occurred.
2. The `MutationObserver` which invoked the
 `callback`. This is most often used to disconnect the observer using `MutationObserver.disconnect()`.

See the examples below for more details.

### Return value

 A new `MutationObserver` object, configured to call the specified
 `callback` when DOM mutations occur.

Examples
--------

### Observing child elements

This example has buttons to add an `<li>` element to a list, and to remove the first `<li>` element from the list.

We use a `MutationObserver` to be notified about changes to the list. In the callback, we log additions and removals, and as soon as the list is empty, we disconnect the observer.

The "Reset example" button resets the example to its original state.

#### HTML

```html
<button id="add">Add child</button>
<button id="remove">Remove child</button>
<button id="reset">Reset example</button>

<ul id="container"></ul>

<pre id="log"></pre>
```

#### CSS

```css
#container,
#log {
  height: 150px;
  overflow: scroll;
}

#container li {
  background-color: paleturquoise;
  margin: 0.5rem;
}
```

#### JavaScript

```js
const add = document.querySelector("#add");
const remove = document.querySelector("#remove");
const reset = document.querySelector("#reset");
const container = document.querySelector("#container");
const log = document.querySelector("#log");

let namePrefix = 0;

add.addEventListener("click", () => {
  const newItem = document.createElement("li");
  newItem.textContent = `item ${namePrefix}`;
  container.appendChild(newItem);
  namePrefix++;
});

remove.addEventListener("click", () => {
  const itemToRemove = document.querySelector("li");
  if (itemToRemove) {
    itemToRemove.parentNode.removeChild(itemToRemove);
  }
});

reset.addEventListener("click", () => {
  document.location.reload();
});

function logChanges(records, observer) {
  for (const record of records) {
    for (const addedNode of record.addedNodes) {
      log.textContent = `Added: ${addedNode.textContent}\n${log.textContent}`;
    }
    for (const removedNode of record.removedNodes) {
      log.textContent = `Removed: ${removedNode.textContent}\n${log.textContent}`;
    }
    if (record.target.childNodes.length === 0) {
      log.textContent = `Disconnected\n${log.textContent}`;
      observer.disconnect();
    }
    console.log(record.target.childNodes.length);
  }
}

const observerOptions = {
  childList: true,
  subtree: true,
};

const observer = new MutationObserver(logChanges);
observer.observe(container, observerOptions);
```

#### Result

Try clicking "Add child" to add list items, and "Remove child" to remove them. The observer callback logs additions and removals. As soon as the list is empty, the observer logs a "Disconnected" message and disconnects the observer.

The "Reset example" button reloads the example so you can try it again.

Specifications
--------------

| Specification |
| --- |
| DOM Standard # ref-for-dom-mutationobserver-mutationobserver① |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


MutationObserver: disconnect() method - Web APIs

MutationObserver: disconnect() method
=====================================

 The `MutationObserver` method
 **`disconnect()`** tells the observer to stop watching for
 mutations.

 The observer can be reused by calling its
 `observe()` method again.

Syntax
------

```js
disconnect()
```

### Parameters

None.

### Return value

`undefined`.

**Note:** All notifications of mutations that have already been
 *detected*, but *not yet reported* to the observer, are discarded.
 To hold on to and handle the detected but unreported mutations, use
 the `takeRecords()` method.

Usage notes
-----------

 If the element being observed is removed from the DOM, and then subsequently released
 by the browser's garbage collection mechanism, the `MutationObserver` will stop observing
 the removed element. However, the `MutationObserver` itself can continue to exist to observe
 other existing elements.

Examples
--------

 This example creates an observer, then disconnects from it, leaving it available for
 possible reuse.

```js
const targetNode = document.querySelector("#someElement");
const observerOptions = {
  childList: true,
  attributes: true,
};

const observer = new MutationObserver(callback);
observer.observe(targetNode, observerOptions);

/\* some time later… \*/

observer.disconnect();
```

Specifications
--------------

| Specification |
| --- |
| DOM Standard # ref-for-dom-mutationobserver-disconnect① |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


XRCPUDepthInformation: data property - Web APIs

XRCPUDepthInformation: data property
====================================

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The *read-only* **`data`** property of the `XRCPUDepthInformation` interface is an `ArrayBuffer` containing depth-buffer information in raw format.

The data is stored in row-major format, without padding, with each entry corresponding to distance from the view's near plane to the users' environment, in unspecified units. The size of each data entry and the type is determined by `depthDataFormat`. The values can be converted from unspecified units to meters by multiplying them by `rawValueToMeters`. The `normDepthBufferFromNormView` property can be used to transform from normalized view coordinates (an origin in the top left corner of the view, with X axis growing to the right, and Y axis growing downward) into the depth buffer's coordinate system.

Value
-----

An `ArrayBuffer`.

Examples
--------

Use `XRFrame.getDepthInformation()` to obtain depth information. The returned `XRCPUDepthInformation` object will contain the `data` buffer.

For CPU depth information and a buffer that has "luminance-alpha" format:

```js
const uint16 = new Uint16Array(depthInfo.data);
const index = column + row \* depthInfo.width;
const depthInMeters = uint16[index] \* depthInfo.rawValueToMeters;
```

(Use `Float32Array` for a "float32" data format.)

Note that the depth in meters is in depth-buffer coordinates. Additional steps are needed to convert them to normalized view coordinates, or the `XRCPUDepthInformation.getDepthInMeters()` method can be used.

Specifications
--------------

| Specification |
| --- |
| WebXR Depth Sensing Module # dom-xrcpudepthinformation-data |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.