diff --git a/source b/source index 2529743aa6e..da353fac63d 100644 --- a/source +++ b/source @@ -2639,6 +2639,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
  • primary interface
  • interface object
  • include
  • +
  • inherit
  • interface prototype object
  • [[Realm]] field of a platform object
  • callback context
  • @@ -3970,18 +3971,6 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute -
    Worklets
    - -
    -

    The following feature is defined in Worklets:

    - - -
    -
    Cooperative Scheduling of Background Tasks
    @@ -79393,6 +79382,11 @@ dictionary WindowPostMessageOptions : PostMessageOptions
  • Remove document from the owner set of each WorkerGlobalScope object whose set contains document.

  • + +
  • For each workletGlobalScope in + document's worklet global + scopes, terminate + workletGlobalScope.

  • To discard a browsing @@ -79661,12 +79655,12 @@ interface BarProp {

    1. Set settings object's id to - reservedEnvironment's id, settings - object's target browsing - context to reservedEnvironment's target browsing context, and - settings object's active - service worker to reservedEnvironment's reservedEnvironment's id, target browsing context to + reservedEnvironment's target browsing context, and active service worker to + reservedEnvironment's active service worker.

    2. @@ -88322,7 +88316,7 @@ interface ApplicationCache : EventTarget { obtaining a worker/worklet agent given outside settings, isShared, and true.

      -

      To obtain a worklet agent, given an environment settings object +

      To obtain a worklet agent, given an environment settings object outside settings, return the result of obtaining a worker/worklet agent given outside settings, false, and false.

      @@ -89201,15 +89195,9 @@ document.querySelector("button").addEventListener("click", bound);
    3. -

      If global is a WorkletGlobalScope, then:

      +

      If global is a WorkletGlobalScope, then return true.

      -
        -
      1. If global's owner - document's relevant settings object is a secure context, - then return true.

      2. - -
      3. Return false.

      4. -
      +

      Worklets can only be created in secure contexts.

    @@ -89772,37 +89760,50 @@ document.querySelector("button").addEventListener("click", bound);

    To fetch a module worker script graph given a url, a fetch client settings object, a destination, a - credentials mode, and a module map settings object, run these steps. The - algorithm will asynchronously complete with either null (on failure) or a module - script (on success).

    + credentials mode, and a module map settings object, fetch a + worklet/module worker script graph given url, fetch client settings + object, destination, credentials mode, and module map settings + object, asynchronously completing with the asynchronous completion result of that + algorithm.

    + +

    To fetch a worklet script graph given a url, a fetch client settings + object, a destination, a credentials mode, a module map settings + object, and a module responses map, fetch a worklet/module worker script + graph given url, fetch client settings object, + destination, credentials mode, and module map settings object, + asynchronously completing with the asynchronous completion result of that algorithm. Use the + following custom steps to perform the fetch + given response:

      -
    1. Let options be a script fetch options whose cryptographic nonce is the empty string, integrity metadata is the empty string, - parser metadata is "not-parser-inserted", credentials mode is credentials - mode, and referrer - policy is the empty string.

      +
    2. Let requestURL be request's url.

    3. -
    4. Fetch a single module script given url, fetch client settings - object, destination, options, module map settings object, - "client", and with the top-level module fetch flag set. If the - caller of this algorithm specified custom perform - the fetch steps, pass those along as well. Wait until the algorithm asynchronously - completes with result.

    5. +
    6. If moduleResponsesMap[requestURL] is "fetching", wait in parallel until that entry's value changes, then + queue a task on the networking task source to proceed with running the + following steps.

    7. -
    8. If result is null, asynchronously complete this algorithm with null, and - return.

    9. +
    10. If moduleResponsesMap[requestURL] exists, then asynchronously complete the perform the fetch steps with + moduleResponsesMap[requestURL].

    11. -
    12. Let visited set be « url ».

    13. +
    14. Set moduleResponsesMap[requestURL] to + "fetching".

    15. -
    16. Fetch the - descendants of and link result given fetch client settings - object, destination, and visited set. When this asynchronously - completes with final result, asynchronously complete this algorithm with final - result.

    17. +
    18. +

      Fetch request. To process + response for the response response:

      + +
        +
      1. Set moduleResponsesMap[requestURL] to + response.

      2. + +
      3. Asynchronously complete the perform the + fetch steps with response.

      4. +
      +

    @@ -89814,7 +89815,7 @@ document.querySelector("button").addEventListener("click", bound);

    This diagram illustrates how these algorithms relate to the ones above, as well as to each other:

    - + fetch an external module script graph - + @@ -89856,7 +89857,7 @@ document.querySelector("button").addEventListener("click", bound); fetch an import() module script graph - + @@ -89864,7 +89865,7 @@ document.querySelector("button").addEventListener("click", bound); fetch a modulepreload module script graph - + @@ -89872,7 +89873,7 @@ document.querySelector("button").addEventListener("click", bound); fetch an inline module script graph - + @@ -89880,33 +89881,83 @@ document.querySelector("button").addEventListener("click", bound); fetch a module worker script graph - + + + + + + fetch a worklet script graph + + + - + + + + fetch a worklet/module worker script graph + + + + + fetch the descendants of and link a module script - + - + fetch the descendants of a module script - + - + internal module script graph fetching procedure - + +

    To fetch a worklet/module worker script graph given a url, a fetch + client settings object, a destination, a credentials mode, and a + module map settings object, run these steps. The algorithm will asynchronously complete + with either null (on failure) or a module script (on success).

    + +
      +
    1. Let options be a script fetch options whose cryptographic nonce is the empty string, integrity metadata is the empty string, + parser metadata is "not-parser-inserted", credentials mode is credentials + mode, and referrer + policy is the empty string.

      + +
    2. Fetch a single module script given url, fetch client settings + object, destination, options, module map settings object, + "client", and with the top-level module fetch flag set. If the + caller of this algorithm specified custom perform + the fetch steps, pass those along as well. Wait until the algorithm asynchronously + completes with result.

    3. + +
    4. If result is null, asynchronously complete this algorithm with null, and + return.

    5. + +
    6. Let visited set be « url ».

    7. + +
    8. Fetch the + descendants of and link result given fetch client settings + object, destination, and visited set. When this asynchronously + completes with final result, asynchronously complete this algorithm with final + result.

    9. +
    +

    To fetch the descendants of and link a module script module script, given a fetch client settings object, a destination, and a visited set, run these steps. The algorithm will asynchronously complete with either @@ -90642,16 +90693,18 @@ document.querySelector("button").addEventListener("click", bound); "Script error.", urlString to the empty string, line and col to 0, and errorValue to null.

    -
  • Let notHandled be the result of firing an - event named error at target, using - ErrorEvent, with the cancelable attribute - initialized to true, the message attribute - initialized to message, the filename - attribute initialized to urlString, the lineno attribute initialized to line, the colno attribute initialized to col, and the error attribute initialized to - errorValue.

  • +
  • Let notHandled be true.

  • + +
  • If target implements EventTarget, then set notHandled + to the result of firing an event named error at target, using ErrorEvent, with the + cancelable attribute initialized to true, the message attribute initialized to message, the + filename attribute initialized to + urlString, the lineno attribute + initialized to line, the colno attribute + initialized to col, and the error attribute + initialized to errorValue.

  • Let target no longer be in error reporting mode.

  • @@ -100476,8 +100529,8 @@ interface SharedWorkerGlobalScope : WorkerGlobalScope { issue #207 for more details.

    -
  • Execute the Initialize a global object's CSP list - algorithm on worker global scope and response.

  • +
  • Initialize a global object's CSP list given worker global scope + and response.

  • Asynchronously complete the perform the fetch steps with response.

  • @@ -100703,10 +100756,9 @@ interface SharedWorkerGlobalScope : WorkerGlobalScope {
    Script settings for workers
    -

    When the user agent is required to set up a worker environment settings object, - given a JavaScript execution context execution context and - environment settings object outside settings, it must run the following - steps:

    +

    To set up a worker environment settings object, given a JavaScript execution + context execution context and environment settings object + outside settings:

    1. Let inherited origin be outside settings's SharedWorkerGlobalScope : WorkerGlobalScope {

    2. Set settings object's id to a new - unique opaque string, settings object's creation URL to worker global - scope's url, settings object's top-level creation URL - to null, settings object's target browsing context to null, and - settings object's active - service worker to null.

    3. + unique opaque string, creation URL to + worker global scope's url, top-level creation URL to null, + target browsing context to + null, and active service worker + to null.

    4. If worker global scope is a DedicatedWorkerGlobalScope object, then set settings object's top-level origin to outside @@ -101404,6 +101454,850 @@ interface WorkerLocation {

    +

    Worklets

    + +

    Introduction

    + + + +

    Worklets are a piece of specification infrastructure which can be used for running scripts + independent of the main JavaScript execution environment, while not requiring any particular + implementation model.

    + +

    The worklet infrastructure specified here cannot be used directly by web developers. Instead, + other specifications build upon it to create directly-usable worklet types, specialized for + running in particular parts of the browser implementation pipeline.

    + +

    Motivations

    + + + +

    Allowing extension points to rendering, or other sensitive parts of the implementation pipeline + such as audio output, is difficult. If extension points were done with full access to the APIs + available on Window, engines would need to abandon previously-held assumptions for + what could happen in the middle of those phases. For example, during the layout phase, rendering + engines assume that no DOM will be modified.

    + +

    Additionaly, defining extension points in the Window environment would restrict + user agents to performing work in the same thread as the Window object. (Unless + implementations added complex, high-overhead infrastructure to allow thread-safe APIs, as well + as thread-joining guarantees.)

    + +

    Worklets are designed to allow extension points, while keeping guarantees that user agents + currently rely on. This is done through new global environments, based on subclasses of + WorkletGlobalScope.

    + +

    Worklets are similar to web workers. However, they:

    + +
      +
    • Are thread-agnostic. That is, they are not designed to run on a dedicated separate thread, + like each worker is. Implementations can run worklets wherever they choose (including on the main + thread).

    • + +
    • Are able to have multiple duplicate instances of the global scope created, for the purpose + of parallelism.

    • + +
    • Do not use an event-based API. Instead, classes are registered on the global scope, whose + methods are invoked by the user agent.

    • + +
    • Have a reduced API surface on the global scope.

    • + +
    • Have a lifetime for their global object which is defined by other + specifications, often in an implementation-defined manner.

    • +
    + +

    As worklets have relatively high overhead, they are best used sparingly. Due to this, a given + WorkletGlobalScope is expected to be shared between multiple separate scripts. (This + is similar to how a single Window is shared between multiple separate scripts.)

    + +

    Worklets are a general technology that serve different use cases. Some worklets, such as those + defined in CSS Painting API, provide extension points intended for stateless, + idempotent, and short-running computations, which have special considerations as described in the + next couple of sections. Others, such as those defined in Web Audio API, are used for + stateful, long-running operations.

    + +

    Code idempotence

    + +

    Some specifications which use worklets are intended to allow user agents to parallelize work + over multiple threads, or to move work between threads as required. In these specifications, user + agents might invoke methods on a web-developer-provided class in an + implementation-defined order.

    + +

    As a result of this, to prevent interoperability issues, authors who register classes on such + WorkletGlobalScopes should make their code idempotent. That is, a method or set of + methods on the class should produce the same output given a particular input.

    + +

    This specification uses the following techniques in order to encourage authors to write code in + an idempotent way:

    + +
      +
    • +

      No reference to the global object is available (i.e., there is no counterpart to self on WorkletGlobalScope.

      + +

      Although this was the intention when worklets were first specified, the + introduction of globalThis has made it no longer true. See issue #6059 for more discussion.

      +
    • + +
    • Code is loaded as a module script, which results in the code being executed + in strict mode and with no shared this referencing the global + proxy.

    • +
    + +

    Together, these restrictions help prevent two different scripts from sharing state using + properties of the global object.

    + +

    Additionally, specifications which use worklets and intend to allow + implementation-defined behavior must obey the following:

    + +
      +
    • They must require user agents to always have at least two WorkletGlobalScope + instances per Worklet, and randomly assign a method or set of methods on a class to + a particular WorkletGlobalScope instance. These specifications may provide an + opt-out under memory constraints.

    • + +
    • These specifications must allow user agents to create and destroy instances of their + WorkletGlobalScope subclasses at any time.

    • +
    + +

    Speculative evaluation

    + +

    Some specifications which use worklets can invoke methods on a web-developer-provided class + based on the state of the user agent. To increase concurrency between threads, a user agent may + invoke a method speculatively, based on potential future states.

    + +

    In these specifications, user agents might invoke such methods at any time, and with any + arguments, not just ones corresponding to the current state of the user agent. The reuslts of such + speculative evaluations are not displayed immediately, but can be cached for use if the user agent + state matches the speculated state. This can increase the concurrency between the user agent and + worklet threads.

    + +

    As a result of this, to prevent interoperability risks between user agents, authors who + register classes on such WorkletGlobalScopes should make their code stateless. That + is, the only effect of invoking a method should be its result, and not any side effects such as + updating mutable state.

    + +

    The same techniques which encourage code idempotence also + encourage authors to write stateless code.

    + +
    + +

    Examples

    + + + +

    For these examples, we'll use a fake worklet. The Window object provides two + Worklet instances, which each run code in their own collection of + FakeWorkletGlobalScopes: + +

    partial interface Window {
    +  [SameObject, SecureContext] readonly attribute Worklet fakeWorklet1;
    +  [SameObject, SecureContext] readonly attribute Worklet fakeWorklet2;
    +};
    + +
    +
    window . fakeWorklet1
    +
    Returns one of the fake worklets.
    + +
    window . fakeWorklet2
    +
    Returns another of the fake worklets.
    +
    + +

    Each Window has two Worklet instances, fake + worklet 1 and fake worklet 2. Both of these have their worklet + global scope type set to FakeWorkletGlobalScope, and their worklet + destination type set to "fakeworklet". User agents should create at + least two FakeWorkletGlobalScope instances per worklet.

    + +

    "fakeworklet" is not actually a valid destination per Fetch. But this + illustrates how real worklets would generally have their own worklet-type-specific destination. +

    + +
    + +

    The fakeWorklet1 getter steps are to return + this's fake worklet 1.

    + +

    The fakeWorklet2 getter steps are to return + this's fake worklet 2.

    + +
    + +
    + +
    [Global=(Worklet,FakeWorklet),
    + Exposed=FakeWorklet,
    + SecureContext]
    +interface FakeWorkletGlobalScope {
    +  undefined registerFake(DOMString type, Function classConstructor);
    +};
    + +

    Inside a FakeWorkletGlobalScope, the following global method is + available:

    + +
    +
    registerFake(type, classConstructor)
    +
    Registers the JavaScript class given by classConstructor for use when the user + agent later wants to do some operation specified by type.
    +
    + +
    + +

    Each FakeWorkletGlobalScope has a registered class constructors map, + which is an ordered map, initially empty.

    + +

    The registerFake(type, classConstructor) method + steps are to set this's registered class constructors + map[type] to classConstructor.

    + +
    + +

    Loading scripts

    + + + +

    To load scripts into fake worklet 1, a web developer would write:

    + +
    window.fakeWorklet1.addModule('script1.mjs');
    +window.fakeWorklet1.addModule('script2.mjs');
    + +

    Note that which script finishes fetching and runs first is dependent on network timing: it + could be either script1.mjs or script2.mjs. This + generally won't matter for well-written scripts intended to be loaded in worklets, if they follow + the suggestions about preparing for speculative + evaluation.

    + +

    If a web developer wants to perform a task only after the scripts have successfully run and + loaded into some worklets, they could write:

    + +
    Promise.all([
    +    window.fakeWorklet1.addModule('script1.mjs'),
    +    window.fakeWorklet2.addModule('script2.mjs')
    +]).then(() => {
    +    // Do something which relies on those scripts being loaded.
    +});
    + +
    + +

    Another important point about script-loading is that loaded scripts can be run in multiple + WorkletGlobalScopes per Worklet, as discussed in the section on code idempotence. In particular, the specification above + for fake worklet 1 and fake worklet 2 require this. So, consider a + scenario such as the following:

    + +
    // script.mjs
    +console.log("Hello from a FakeWorkletGlobalScope!");
    + +
    // app.mjs
    +window.fakeWorklet1.addModule("script.mjs");
    + +

    This could result in output such as the following from a user agent's console:

    + +
    [fakeWorklet1#1] Hello from a FakeWorkletGlobalScope!
    +[fakeWorklet1#4] Hello from a FakeWorkletGlobalScope!
    +[fakeWorklet1#2] Hello from a FakeWorkletGlobalScope!
    +[fakeWorklet1#3] Hello from a FakeWorkletGlobalScope!
    + +

    If the user agent at some point decided to kill and restart the third instance of + FakeWorkletGlobalScope, the console would again print [fakeWorklet1#3] Hello from a FakeWorkletGlobalScope! when this occurs.

    + +

    Registering a class and invoking its methods

    + + + +

    Let's say that one of the intended usages of our fake worklet by web developers is to allow + them to customize the highly-complex process of boolean negation. They might register their + customization as follows:

    + +
    // script.mjs
    +registerFake('negation-processor', class {
    +  process(arg) {
    +    return !arg;
    +  }
    +});
    + +
    // app.mjs
    +window.fakeWorklet1.addModule("script.mjs");
    + +

    To make use of such registered classes, the specification for fake worklets could define a + find the opposite of true algorithm, given a + Worklet worklet, which invokes the process method on any class registered to one of worklet's global + scopes as having type "negation-processor", with true as the argument, and + then uses the result in some way.:

    + +
    + +
      +
    1. Optionally, create a worklet global scope for worklet.

    2. + +
    3. Let workletGlobalScope be one of worklet's global scopes, chosen in an + implementation-defined manner.

    4. + +
    5. Let classConstructor be workletGlobalScope's registered class + constructors map["negation-processor"].

    6. + +
    7. Let classInstance be the result of constructing classConstructor, with + no arguments.

    8. + +
    9. Let function be Get(classInstance, + "process"). Rethrow any exceptions.

      + +
    10. Let callback be the result of converting function to a Web IDL Function instance.

    11. + +
    12. Return the result of invoking + callback with the arguments « true » and with classInstance as the callback this value.

    13. +
    + +

    Another, perhaps better, specification architecture would be to extract the "process" property and convert it into a Function at registration time, as part of the registerFake() method steps.

    + +
    + +
    + +

    Infrastructure

    + +

    The global scope

    + +

    Subclasses of WorkletGlobalScope are used to create global objects wherein code loaded into a particular Worklet can + execute.

    + +
    [Exposed=Worklet, SecureContext]
    +interface WorkletGlobalScope {};
    + +

    Other specifications are intended to subclass WorkletGlobalScope, + adding APIs to register a class, as well as other APIs specific for their worklet type.

    + +
    + +

    Each WorkletGlobalScope has an associated module map. It is a module map, + initially empty.

    + +
    + +
    Agents and event loops
    + + + +

    Each WorkletGlobalScope is contained in its own worklet agent, which + has its corresponding event loop. However, in + practice, implementation of these agents and event loops is expected to be different from most + others.

    + +

    A worklet agent exists for each WorkletGlobalScope since, in theory, + an implementation could use a separate thread for each WorkletGlobalScope instance, + and allowing this level of parallelism is best done using agents. However, because their + [[CanBlock]] value is false, there is no requirement that agents and threads are one-to-one. This + allows implementations the freedom to execute scripts loaded into a worklet on any thread, + including one running code from other agents with [[CanBlock]] of false, such as the thread of a + similar-origin window agent ("the main thread"). Contrast this with dedicated worker agents, whose true value for [[CanBlock]] + effectively requires them to get a dedicated operating system thread.

    + +

    Worklet event loops are also somewhat special. They are only + used for tasks associated with addModule(), tasks wherein the user agent invokes + author-defined methods, and microtasks. Thus, even though the event loop processing model specifies that all event loops + run continuously, implementations can achieve observably-equivalent results using a simpler + strategy, which just invokes author-provided + methods and then relies on that process to perform a microtask checkpoint.

    + +
    + +
    Creation and termination
    + +

    To create a worklet global scope for a Worklet + worklet:

    + +
      +
    1. Let outsideSettings be worklet's relevant settings + object.

    2. + +
    3. Let agent be the result of obtaining a + worklet agent given outsideSettings. Run the rest of these steps in that + agent.

    4. + +
    5. +

      Let realmExecutionContext be the result of creating a new JavaScript + realm given agent and the following customizations:

      + +
        +
      • For the global object, create a new object of the type given by worklet's + worklet global scope type.

      • +
      +
    6. + +
    7. Let workletGlobalScope be the global + object of realmExecutionContext's Realm component.

    8. + +
    9. Let insideSettings be the result of setting up a worklet environment settings object given + realmExecutionContext and outsideSettings.

    10. + +
    11. Initialize a global object's CSP list given workletGlobalScope. +

    12. + +
    13. +

      For each moduleURL of worklet's + added modules list:

      + +
        +
      1. +

        Fetch a worklet script graph given moduleURL, + insideSettings, worklet's worklet destination type, what credentials mode?, insideSettings, and worklet's + module responses map. Wait until + the algorithm asynchronously completes with script.

        + +

        This will not actually perform a network request, as it will just reuse responses from worklet's module responses map. The main + purpose of this step is to create a new workletGlobalScope-specific module + script from the response.

        +
      2. + +
      3. Assert: script is not null, since the fetch succeeded and the source text was + successfully parsed when worklet's module responses map was initially + populated with moduleURL.

      4. + +
      5. Run a module script given script.

      6. +
      +
    14. + +
    15. Append workletGlobalScope to + outsideSettings's global object's + associated Document's worklet global scopes.

    16. + +
    17. Append workletGlobalScope to + worklet's global scopes.

    18. + +
    19. Run the responsible event loop specified by + insideSettings.

    20. +
    + +

    To terminate a worklet global scope given a WorkletGlobalScope + workletGlobalScope:

    + +
      +
    1. Let eventLoop be workletGlobalScope's relevant agent's + event loop.

    2. + +
    3. If there are any tasks queued in eventLoop's + task queues, discard them without processing them.

    4. + +
    5. Wait for eventLoop to complete the currently running + task.

    6. + +
    7. If the previous step doesn't complete within an implementation-defined period + of time, then abort the script currently running in + the worklet.

    8. + +
    9. Destroy eventLoop.

    10. + +
    11. Remove workletGlobalScope from the global scopes of the Worklet whose + global scopes contains + workletGlobalScope.

    12. + +
    13. Remove workletGlobalScope from the worklet global scopes of the + Document whose worklet global + scopes contains workletGlobalScope.

    14. +
    + +
    Script settings for worklets
    + +

    To set up a worklet environment settings object, given a JavaScript + execution context executionContext and an environment settings + object outsideSettings:

    + +
      +
    1. Let origin be a unique opaque + origin.

    2. + +
    3. Let inheritedAPIBaseURL be outsideSettings's API base + URL.

    4. + +
    5. Let inheritedReferrerPolicy be outsideSettings's referrer policy.

    6. + +
    7. Let inheritedEmbedderPolicy be outsideSettings's embedder policy.

    8. + +
    9. Let realm be the value of executionContext's Realm + component.

    10. + +
    11. Let workletGlobalScope be realm's global object.

    12. + +
    13. +

      Let settingsObject be a new environment settings object whose + algorithms are defined as follows:

      + +
      +
      The realm execution context
      +
      +

      Return executionContext.

      +
      + +
      The module map
      +
      +

      Return workletGlobalScope's module map.

      +
      + +
      The responsible document
      +

      Not applicable (the responsible event loop is not a window event + loop).

      + +
      The API URL character encoding
      +
      +

      Return UTF-8.

      +
      + +
      The API base URL
      +
      +

      Return inheritedAPIBaseURL.

      + +

      Unlike workers or other globals derived from a single resource, worklets have + no primary resource; instead, multiple scripts, each with their own URL, are loaded into the + global scope via worklet.addModule(). So this API base URL + is rather unlike that of other globals. However, so far this doesn't matter, as no APIs + available to worklet code make use of the API base URL.

      +
      + +
      The origin
      +
      +

      Return origin.

      +
      + +
      The referrer policy
      +
      +

      Return inheritedReferrerPolicy.

      +
      + +
      The embedder policy
      +
      +

      Return inheritedEmbedderPolicy.

      +
      + +
      The cross-origin + isolated capability
      +

      Return TODO.

      +
      +
    14. + +
    15. Set settingsObject's id to a new + unique opaque string, creation URL to + inheritedAPIBaseURL, top-level creation URL to null, top-level + origin to outsideSettings's top-level origin, target browsing context to null, and + active service worker to + null.

    16. + +
    17. Set realm's [[HostDefined]] field to settingsObject.

    18. + +
    19. Return settingsObject.

    20. +
    + +
    + +

    The Worklet class

    + +

    The Worklet class provides the capability to add module scripts into its + associated WorkletGlobalScopes. The user agent can then create classes registered on + the WorkletGlobalScopes and invoke their methods.

    + +
    [Exposed=Window, SecureContext]
    +interface Worklet {
    +  [NewObject] Promise<undefined> addModule(USVString moduleURL, optional WorkletOptions options = {});
    +};
    +
    +dictionary WorkletOptions {
    +  RequestCredentials credentials = "same-origin";
    +};
    + +

    Specifications that create Worklet instances must specify the following for a + given instance:

    + +
      +
    • its worklet global scope type, which must be a Web IDL type that inherits from WorkletGlobalScope; and

    • + +
    • its worklet destination type, which must be a destination, and is used when fetching + scripts.

    • +
    + +
    +
    await worklet . addModule(moduleURL[, { credentials }])
    +
    +

    Loads and executes the module script given by moduleURL into all of + worklet's global scopes. It can + also create additional global scopes as part of this process, depending on the worklet type. The + returned promise will fulfill once the script has been successfully loaded and run in all global + scopes.

    + +

    The credentials option can be set to a + credentials mode to modify the + script-fetching process. It defaults to "same-origin".

    + +

    Any failures in fetching the script or its + dependencies will cause the returned promise to be rejected with an + "AbortError" DOMException. Any errors in parsing the + script or its dependencies will cause the returned promise to be rejected with the exception + generated during parsing.

    +
    +
    + +
    + +

    A Worklet has a list of global scopes, which contains + instances of the Worklet's worklet global scope type. It is initially + empty.

    + +

    A Worklet has an added modules + list, which is a list of URLs, initially empty. + Access to this list should be thread-safe.

    + +

    A Worklet has a module + responses map, which is an ordered map from URLs to + responses, initially empty. Access to this map should be + thread-safe.

    + +
    +

    The added modules list and module responses map exist to ensure that + WorkletGlobalScopes created at different times get equivalent module scripts run in them, based on the same source text. This allows the + creation of additional WorkletGlobalScopes to be transparent to the author.

    + +

    In practice, user agents are not expected to implement these data structures, and the + algorithms that consult them, using thread-safe programming techniques. Instead, when addModule() is called, user agents can fetch the module + graph on the main thread, and send the fetched source text (i.e., the important data contained in + the module responses map) to each + thread which has a WorkletGlobalScope.

    + +

    Then, when a user agent creates a new + WorkletGlobalScope for a given Worklet, it can simply send the map of + fetched source text and the list of entry points from the main thread to the thread containing + the new WorkletGlobalScope.

    +
    + +

    The addModule(moduleURL, + options) method steps are:

    + +
      +
    1. Let outsideSettings be the relevant settings object of + this.

    2. + +
    3. Parse moduleURL relative to + outsideSettings.

    4. + +
    5. If this fails, then return a promise rejected with a + "SyntaxError" DOMException.

    6. + +
    7. Let moduleURLRecord be the resulting URL record.

    8. + +
    9. Let promise be a new promise.

    10. + +
    11. +

      Run the following steps in parallel:

      + +
        +
      1. +

        If this's global scopes + is empty, then:

        + +
          +
        1. Create a worklet global scope given this.

        2. + +
        3. Optionally, create additional + global scope instances given this, depending on the specific worklet in question + and its specification.

        4. + +
        5. Wait for all steps of the creation + process(es) — including those taking place within the worklet + agents — to complete, before moving on.

        6. +
        +
      2. + +
      3. Let pendingTasks be this's global scopes's size.

      4. + +
      5. Let addedSuccessfully be false.

      6. + +
      7. +

        For each workletGlobalScope of + this's global scopes, + queue a global task on the networking task source given + workletGlobalScope to perform the following steps:

        + +
          +
        1. +

          Fetch a worklet script graph given moduleURLRecord, + outsideSettings, this's worklet destination type, + options["credentials"], + workletGlobalScope's relevant settings object, and + this's module responses + map. Wait until the algorithm asynchronously completes with + script.

          + +

          Only the first of these fetches will actually perform a network request; the + ones for other WorkletGlobalScopes will reuse reuse responses from this's module responses map.

          +
        2. + +
        3. +

          If script is null, then:

          + +
            +
          1. +

            Queue a global task on the networking task source given + this's relevant global object to perform the following + steps:

            + +
              +
            1. +

              If pendingTasks is not −1, then:

              + +
                +
              1. Set pendingTasks to −1.

              2. + +
              3. Reject promise with an "AbortError" + DOMException.

              4. +
              +
            2. +
            +
          2. + +
          3. Abort these steps.

          4. +
          +
        4. + +
        5. +

          If script's error to + rethrow is not null, then:

          + +
            +
          1. +

            Queue a global task on the networking task source given + this's relevant global object to perform the following + steps:

            + +
              +
            1. +

              If pendingTasks is not −1, then:

              + +
                +
              1. Set pendingTasks to −1.

              2. + +
              3. Reject promise with script's error to rethrow.

              4. +
              +
            2. +
            +
          2. + +
          3. Abort these steps.

          4. +
          +
        6. + +
        7. +

          If addedSuccessfully is false, then:

          + +
            +
          1. Append moduleURLRecord to + this's added modules + list.

          2. + +
          3. Set addedSuccessfully to true.

          4. +
          +
        8. + +
        9. Run a module script given script.

        10. + +
        11. +

          Queue a global task on the + networking task source given this's relevant global + object to perform the following steps:

          + +
            +
          1. +

            If pendingTasks is not −1, then:

            + +
              +
            1. Set pendingTasks to pendingTasks − 1.

            2. + +
            3. If pendingTasks is 0, then resolve promise.

            4. +
            +
          2. +
          +
        12. +
        +
      8. +
      +
    12. + +
    13. Return promise.

    14. +
    + +
    + +

    The worklet's lifetime

    + +

    The lifetime of a Worklet has no special considerations; it is tied to the object + it belongs to, such as the Window.

    + +
    + +

    Each Document has a worklet + global scopes, which is a set of WorkletGlobalScopes, initially + empty.

    + +
    + +

    The lifetime of a WorkletGlobalScope is, at a minimum, tied to the + Document whose worklet global + scopes contain it. In particular, discarding the + Document will terminate the + corresponding WorkletGlobalScope and allow it to be garbage-collected.

    + +

    Additionally, specifications which inherit from WorkletGlobalScope and define + specific worklet types can give more specific details on when to create or terminate + the WorkletGlobalScopes for a given worklet type. For example, they might create them + during specific processes that call upon worklet code, as in the example. Or they might terminate them if the + worklet agent's event loop has no + tasks queued, or if the user agent has no pending operations + planning to make use of the worklet, or if the user agent detects abnormal operations such as + infinite loops or callbacks exceeding imposed time limits.

    + +

    Web storage

    Introduction

    @@ -122972,6 +123866,9 @@ INSERT INTERFACES HERE
    [CSSOVERFLOW]
    CSS Overflow Module, L. Baron, F. Rivoal. W3C.
    +
    [CSSPAINT]
    +
    (Non-normative) CSS Painting API, I. Kilpatrick, D. Jackson. W3C.
    +
    [CSSPOSITION]
    CSS Positioned Layout, R. Atanassov, A. Eicholz. W3C.
    @@ -123365,6 +124262,9 @@ INSERT INTERFACES HERE
    [WEBANIMATIONS]
    Web Animations, B. Birtles, S. Stephens, D. Stockwell. W3C.
    +
    [WEBAUDIO]
    +
    (Non-normative) Web Audio API, P. Adenot, H. Choi. W3C.
    +
    [WEBCRYPTO]
    (Non-normative) Web Cryptography API, M. Watson. W3C.
    @@ -123386,9 +124286,6 @@ INSERT INTERFACES HERE
    [WHATWGWIKI]
    The WHATWG Wiki. WHATWG.
    -
    [WORKLETS]
    -
    Worklets. I. Kilpatrick. W3C.
    -
    [WSP]
    The WebSocket protocol, I. Fette, A. Melnikov. IETF.
    @@ -124519,6 +125416,10 @@ INSERT INTERFACES HERE William Chen for their contributions.

    +

    Special thanks to the CSSWG for developing + the worklets. In particular, thanks to Ian Kilpatrik for his work as + editor of the original worklets specification.

    +

    For about ten years starting in 2003, this standard was almost entirely written by Ian Hickson (Google, ian@hixie.ch). More recently, @@ -124616,6 +125517,13 @@ INSERT INTERFACES HERE repository, which is available under CC0.

    +

    Part of the revision history of the worklets feature can be found in the w3c/css-houdini-drafts + repository, which is available under the W3C Software and + Document License.

    +

    Copyright © WHATWG (Apple, Google, Mozilla, Microsoft). This work is licensed under a Creative Commons Attribution 4.0 International License.