diff --git a/css-layout-api/Overview.bs b/css-layout-api/Overview.bs index 6074248e..aaf5b5af 100644 --- a/css-layout-api/Overview.bs +++ b/css-layout-api/Overview.bs @@ -16,7 +16,6 @@ Former Editor: Shane Stephens, shanestephens@google.com, w3cid 47691 Editor: Robert O'Callahan, robert@ocallahan.org Editor: Rossen Atanassov, rossen.atanassov@microsoft.com, w3cid 49885 Ignored Terms: LayoutWorklet -Ignored Terms: create a workletglobalscope - -
-spec:fetch; type:dfn; for:/; text:fetch -spec:html; type:dfn; for:/; text:browsing context -spec:html; type:interface; for:/; text:Document -spec:webidl; type:dfn; for:interface; text:inherit -spec:url; type:dfn; text:url; for:url -spec:html; type:dfn; for:/; text:event loop -- -
-urlPrefix: https://fetch.spec.whatwg.org/; type: dfn; - urlPrefix: #concept-; - text: fetch -urlPrefix: https://html.spec.whatwg.org/multipage/browsers.html; type: dfn; - text: effective script origin - url: #origin-2; text: origin -urlPrefix: http://heycam.github.io/webidl/; type: dfn; - urlPrefix: #es-; - text: invoking callback functions -urlPrefix: https://html.spec.whatwg.org/multipage/workers.html; type: dfn; - urlPrefix: #dom-workerglobalscope-; - text: self -urlPrefix: https://html.spec.whatwg.org/multipage/webappapis.html; type: dfn; - text: document environment - text: event loop processing model - text: microtask queue - text: task queues - text: discarded; url: a-browsing-context-is-discarded -urlPrefix: https://w3c.github.io/webappsec-csp/#; type: dfn; - text: initialize a global object's CSP list; url: initialize-global-object-csp -urlPrefix: http://www.ecma-international.org/ecma-262/6.0/#sec-; type: dfn; - text: Construct - text: InitializeHostDefinedRealm - text: Invoke - text: strict mode code -- -Introduction {#intro} -===================== - -Motivations {#motivations} --------------------------- - -This section is not normative. - -Allowing extension points defined in the document environment is difficult, as rendering -engines would need to abandon previously held assumptions for what could happen in the middle of a -phase. - -For example, during the layout phase the rendering engine assumes that no DOM will be modified. - -Additionally defining extension points in the document environment would restrict rendering -engines to performing work in the same thread as the document environment. (Unless rendering -engines added complex, high-overhead infrastructure to allow thread-safe APIs in addition to thread -joining guarantees). - -The worklet is designed to allow such extension points in rendering engines, while keeping -guarantees which rendering engines rely currently on. - -Worklets are similar to web workers however they: - - Are thread-agnostic. That is, they are not defined to run on a particular thread. Rendering - engines may run them wherever they choose. - - Are able to have multiple duplicate instances of the global scope created for the purpose of - parallelism. - - Are not event API based. Instead classes are registered on the global scope, whose methods are to - be invoked by the user agent. - - Have a reduced API surface on the global scope. - - Have a lifetime for the global scope which is defined by subsequent specifications or user - agents. They aren't tied to the lifetime of the document. - -As worklets have a relatively high overhead, they should be used sparingly. Due to this worklets are -expected to be shared between separate scripts. This is similar to the document environment. - -Code Idempotency {#code-idempotency} ------------------------------------- - -Some specifications which use worklets ([[css-paint-api-1]]), 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 class in a different order to other -user agents. - -As a result of this, to prevent this compatibility risk between user agents, authors who register -classes on the global scope using these APIs, should make their code idempotent. That is, a method -or set of methods on a class should produce the same output given a particular input. - -The following techniques are used in order to encourage authors to write code in an idempotent way: - - - No reference to the global object, e.g. self on a {{DedicatedWorkerGlobalScope}}. - - - Code is loaded as a module script which resulting in the code being executed in strict - mode code without a shared this. This prevents two different module scripts sharing - state by referencing shared objects on the global scope. - - - These specifications must require user agents to always have at least two {{WorkletGlobalScope}}s - per {{Worklet}} and randomly assign a method or set of methods on a class to a particular - global scope. These specifications can provide an opt-out under memory constraints. - - - User agents can create and destroy {{WorkletGlobalScope}}s at any time for these specifications. - -Speculative Evaluation {#speculative-evaluation} ------------------------------------------------- - -Some specifications which use worklets ([[css-paint-api-1]]) may invoke methods on a class based on -the state of the user agent. To increase the concurrency between threads, a user agent may invoke a -method speculatively, based on potential future states. - -In these specifications user agents might invoke methods on a class at any time, and with any -arguments, not just ones corresponding to the current state of the user agent. The results of such -speculative evaluations are not displayed immediately, but may be cached for use if the user agent -state matches the speculated state. This may increase the concurrency between the user agent and -worklet threads. - -As a result of this, to prevent this compatibility risk between user agents, authors who register -classes on the global scope using these APIs, should make their code stateless. That is, the only -effect of invoking a method should be its result, not any side-effects such as updating mutable -state. - -The same techniques which encourage code idempotence also encourage authors to write stateless code. - -Infrastructure {#infrastructure} -================================ - -The Global Scope {#the-global-scope} ------------------------------------- - -The {{WorkletGlobalScope}} object provides a worklet global scope which represents the -global execution context of a {{Worklet}}. - -
-[Exposed=Worklet] -interface WorkletGlobalScope { -}; -- -Each {{WorkletGlobalScope}} has an assocated owner -document. -It is initially null and set inside the create a WorkletGlobalScope algorithm. - -Whenever a {{Document}} object is discarded, each {{WorkletGlobalScope}} whose owner -document is that {{Document}} object, should clear its owner document. - -Each {{WorkletGlobalScope}} has an associated environment settings object. - -Each {{WorkletGlobalScope}} has an associated module map. It is a -module map, initially empty. - -Each {{WorkletGlobalScope}} has a worklet global scope execution environment. This -execution environment may be parallel (i.e. it may be on a separate thread, process, or other -equivalent construct), or it may live on the same thread or process as the {{Worklet}} object it -belongs to. Which thread or process it lives on is decided by the user agent. - -Note: - The {{WorkletGlobalScope}} has a limited global scope when compared to a - {{DedicatedWorkerGlobalScope}}. It is expected that other specifications will extend - {{WorkletGlobalScope}} with
registerAClass
methods which
- will allow authors to register classes for the user agent create and invoke methods on.
-
-When asked to report an exception, do nothing instead, or optionally report the exception to
-a developer console.
-
-Issue(whatwg/html#2611): HTML's report an exception needs updating to work with
- non-EventTarget global objects.
-
-### The event loop ### {#the-event-loop}
-
-Each {{WorkletGlobalScope}} object has a distinct event loop. This event loop has no
-associated browsing context. The event loop is created by the create a
-WorkletGlobalScope algorithm.
-
-The event loop is run on the worklet global scope execution environment defined above.
-
-It is expected that only tasks associated {{Worklet/addModule()}}, the user agent invoking author
-defined callbacks, and microtasks will use this event loop.
-
-Note:
- Even through the event loop processing model specifies that it loops continually,
- practically implementations aren't expected to do this. The microtask queue is emptied
- while invoking callback functions provided by the author.
-
-### Creating a WorkletGlobalScope ### {#creating-a-workletglobalscope}
-
--[Exposed=Window] -interface Worklet { - [NewObject] Promise<undefined> addModule(USVString moduleURL, optional WorkletOptions options = {}); -}; - -dictionary WorkletOptions { - RequestCredentials credentials = "same-origin"; -}; -- -A {{Worklet}} has a worklet global scope type. This is used for creating new -{{WorkletGlobalScope}} and the type must inherit from {{WorkletGlobalScope}}. - -Note: As an example the worklet global scope type might be a {{PaintWorkletGlobalScope}}. - -A {{Worklet}} has a list of the worklet's WorkletGlobalScopes. Initially this list -is empty; it is populated when the user agent chooses to create its {{WorkletGlobalScope}}. - -A {{Worklet}} has a worklet destination type. This is used for setting the destination requests from fetch a module worker script graph. - -A {{Worklet}} has a module responses map. This is a ordered map of module URLs to values -that are a fetch responses. The map's entries are ordered based on their insertion order. -Access to this map should be thread-safe. - -The module responses map exists to ensure that {{WorkletGlobalScope}}s created at different -times contain the same set of script source text and have the same behaviour. The creation of -additional {{WorkletGlobalScope}}s should be transparent to the author. - -
- // script.js - console.log('Hello from a WorkletGlobalScope!'); -- -
- // main.js - await CSS.paintWorklet.addModule('script.js'); -- - Behind the scenes the user agent may load the
script.js
- into 4 global scopes, in which case the debugging tools for the user agent would print:
- - [paintWorklet#1] Hello from a WorkletGlobalScope! - [paintWorklet#4] Hello from a WorkletGlobalScope! - [paintWorklet#2] Hello from a WorkletGlobalScope! - [paintWorklet#3] Hello from a WorkletGlobalScope! -- - If the user agent decided to kill and restart a {{WorkletGlobalScope}} number 3 in this example, - it would print
[paintWorklet#3] Hello from a
- WorkletGlobalScope!
again in the debugging tools when this occurs.
-- partial interface Window { - [SameObject] readonly attribute Worklet fakeWorklet1; - [SameObject] readonly attribute Worklet fakeWorklet2; - }; -- -
- [Global=(Worklet,FakeWorklet),Exposed=FakeWorklet] - interface FakeWorkletGlobalScope : WorkletGlobalScope { - void registerAnArbitaryClass(DOMString type, Function classConstructor); - }; -- - Each {{FakeWorkletGlobalScope}} has a map of the registered class constructors map. - - When the - registerAnArbitaryClass(|type|, |classConstructor|) method is called, the user agent will add - the |classConstructor| of |type| to the map of registered class constructors map. -
-window.fakeWorklet1.addModule('script1.js'); -window.fakeWorklet1.addModule('script2.js'); - -// Assuming no other calls to fakeWorklet1 valid script loading orderings are: -// 1. 'script1.js', 'script2.js' -// 2. 'script2.js', 'script1.js' -- -Loading scripts into multiple worklets. {#example-multiple} ------------------------------------------------------------ - -
-Promise.all([ - window.fakeWorklet1.addModule('script1.js'), - window.fakeWorklet2.addModule('script2.js') -]).then(function() { - // Both scripts now have loaded code, can do a task which relies on this. -}); -- -Create a registered class and invoke a method. {#example-class} ---------------------------------------------------------------- - -
-// Inside FakeWorkletGlobalScope -registerAnArbitaryClass('key', class FooClass { - process(arg) { - return !arg; - } -}); -- -As an example, if the user agent wants to invoke "process" on a new class instance, the user agent -could follow the following steps: - 1. Let |workletGlobalScope| be a {{FakeWorkletGlobalScope}} from the list of worklet's - WorkletGlobalScopes from the fake {{Worklet}}. - - The user agent may also create a WorkletGlobalScope given the fake - {{Worklet}} and use that. - - 2. Let |classCtor| be the result of performing a lookup in registered class constructors - map with "key" as the key. - - 3. Let |classInstance| be the result of Construct(|classCtor|). - - 4. Let |result| be the result of Invoke(O=|classInstance|, P="process", - Arguments=["true"]). - - 5. Return |result|. + +