diff --git a/spec/index.bs b/spec/index.bs index 78a380d..417ef4c 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -89,6 +89,7 @@ spec: HTML; urlPrefix: https://html.spec.whatwg.org/multipage/; text: associated Document; for:Window; url: window-object.html#concept-document-window type: dfn text: runnable; for:task; url: webappapis.html#concept-task-runnable + text: posted message task source; url: web-messaging.html#posted-message-task-source spec: dom; urlPrefix: https://dom.spec.whatwg.org/#; type: dfn; text: signal; for: AbortController; url: abortcontroller-signal diff --git a/spec/patches.md b/spec/patches.md index c855ba8..bf39cda 100644 --- a/spec/patches.md +++ b/spec/patches.md @@ -28,28 +28,58 @@ a specific [=task queue=]. With: For each [=event loop=], every [=task source=] that is not a [=scheduler task source=] must be associated with a specific [=task queue=]. +An [=event loop=] object has a numeric next enqueue order, which is +is initialized to 1. + +Note: The [=event loop/next enqueue order=] is a strictly increasing number that is used to +determine task execution order across [=scheduler task queues=] of the same {{TaskPriority}} across +all {{Scheduler}}s associated with the same [=event loop=]. A timestamp would also suffice as long +as it is guaranteed to be strictly increasing and unique. + ### Event loop: processing model ### {#sec-patches-html-event-loop-processing} -Add the following steps to the event loop processing steps, before step 1: - - 1. Let |queues| be the [=set=] of the [=event loop=]'s [=task queues=] that - contain at least one runnable task. - 1. Let |schedulers| be the [=set=] of all {{Scheduler}} objects whose - [=relevant agent's=] [=agent/event loop=] is this event loop and that - [=have a runnable task=]. - 1. If |schedulers| and |queues| are both [=list/empty=], skip to the - microtasks step below. - -Modify step 1 to read: - - 1. Let |taskQueue| be one of the following, chosen in an - [=implementation-defined=] manner: - * If |queues| is not [=list/empty=], one of the [=task queues=] in |queues|, - chosen in an [=implementation-defined=] manner. - * If |schedulers| is not [=list/empty=], the result of - [=selecting the task queue of the next scheduler task=] from one of the - {{Scheduler}}s in |schedulers|, chosen in an [=implementation-defined=] - manner. +Replace: + 1. If the [=event loop=] has a [=task queue=] with at least one runnable + task, then: + 1. Let |taskQueue| be one such [=task queue=], chosen in an [=implementation-defined=] manner. + +With: + 1. Let |queues| be the [=set=] of the [=event loop=]'s [=task queues=] that contain at least one + runnable task. + 1. Let |scheduler queue| be the result of [=selecting the next scheduler queue from all schedulers=] + given the [=event loop=]. + 1. If |scheduler queue| is not null and |queues| is not [=list/empty=], then: + 1. If |scheduler queue|'s [=scheduler task queue/priority=] is {{TaskPriority/user-blocking}}, + then [=set/remove=] from |queues| any [=task queue=] whose [=task source=] is in + «[=timer task source=], [=posted message task source=]». + 1. Otherwise if |scheduler queue|'s [=scheduler task queue/priority=] is + {{TaskPriority/background}}, then set |scheduler queue| to null. + 1. If |scheduler queue| is not null or |queues| is not [=list/empty=], then: + 1. Let |taskQueue| be one of the following, chosen in an [=implementation-defined=] manner: + * One of the [=task queues=] in |queues|, if |queues| is not [=list/empty=]. + * |scheduler queue|'s [=scheduler task queue/tasks=], if |scheduler queue| is not null. + + +Note: This section defines the integration of {{Scheduler}} tasks and the [=event loop=]. +

+The intention of {{TaskPriority/user-blocking}} priority is to enable developers to schedule high +priority work that still stays responsive to input and rendering, e.g. critical work spawned by an +input response that shouldn't block the next frame or key press. {{TaskPriority/user-blocking}} +tasks are specified to have higher event loop priority than other scheduling methods, specifically +{{WindowOrWorkerGlobalScope/setTimeout()|setTimeout(0)}} and same-window +{{Window/postMessage(message, options)|postMessage()}}. UAs have flexibility to prioritize between +{{TaskPriority/user-blocking}} tasks other task sources, but are encouraged to give some increased +priority to the former. One possible strategy is to give {{TaskPriority/user-blocking}} +tasks priority over everything except user input and rendering (to ensure the UI remains +responsive), as well as user-driven tasks like navigation. +

+{{TaskPriority/user-visible}} tasks are meant to be scheduled in a similar way to existing +scheduling mechanisms like {{WindowOrWorkerGlobalScope/setTimeout()|setTimeout(0)}} and +and same-window {{Window/postMessage(message, options)|postMessage()}}, but the relative priority +of these is unspecified (as is the case for all event loop task queues). +

+{{TaskPriority/background}} tasks can only run if no other tasks are runnable. +This is similar to idle tasks, but they can run outside of idle periods. Issue: The |taskQueue| in this step will either be a [=set=] of [=tasks=] or a [=set=] of [=scheduler tasks=]. The steps that follow only [=set/remove=] an diff --git a/spec/scheduling-tasks.md b/spec/scheduling-tasks.md index 0241da1..533de83 100644 --- a/spec/scheduling-tasks.md +++ b/spec/scheduling-tasks.md @@ -133,22 +133,9 @@ single per-{{TaskPriority}} [=scheduler task queue=], and move tasks between [=scheduler task queues=] in response to a {{TaskSignal}}'s [=TaskSignal/priority=] changing, inserting based on [=scheduler task/enqueue order=]. This approach would simplify -[=selecting the task queue of the next scheduler task=], but make priority +[=selecting the next scheduler queue from all schedulers=], but make priority changes more complex. - -A {{Scheduler}} object has a numeric next enqueue order -which is initialized to 1. - -Note: The [=Scheduler/next enqueue order=] is a strictly increasing number that -is used to determine task execution order across [=scheduler task queues=] of the -same {{TaskPriority}} within the same {{Scheduler}}. A logically equivalent -alternative would be to place the [=Scheduler/next enqueue order=] on the -[=event loop=], since the only requirements are that the number be strictly -increasing and not be repeated within a {{Scheduler}}. - -Issue: Would it be simpler to just use a timestamp here? - The postTask(|callback|, |options|) method steps are to return the result of [=scheduling a postTask task=] for [=this=] given |callback| and |options|. @@ -231,7 +218,7 @@ Processing Model {#sec-scheduling-tasks-processing-model}
To schedule a postTask task for {{Scheduler}} |scheduler| given a {{SchedulerPostTaskCallback}} |callback| and - {{SchedulerPostTaskOptions}} |options|, run the following steps: + {{SchedulerPostTaskOptions}} |options|: 1. Let |result| be [=a new promise=]. 1. Let |signal| be |options|["{{SchedulerPostTaskOptions/signal}}"] if @@ -294,8 +281,8 @@ see [whatwg/html#5925](https://github.com/whatwg/html/issues/5925). 1. Let |global| be the [=relevant global object=] for |scheduler|. 1. Let |document| be |global|'s associated `Document` if |global| is a {{Window}} object; otherwise null. - 1. Let |enqueue order| be |scheduler|'s [=Scheduler/next enqueue order=]. - 1. Increment |scheduler|'s [=Scheduler/next enqueue order=] by 1. + 1. Let |enqueue order| be |scheduler|'s [=event loop/next enqueue order=]. + 1. Increment |scheduler|'s [=event loop/next enqueue order=] by 1. 1. Let |task| be the result of [=queuing a scheduler task=] on |queue| given |enqueue order|, [=the posted task task source=], and |document|, and that performs the following steps: @@ -309,7 +296,7 @@ see [whatwg/html#5925](https://github.com/whatwg/html/issues/5925). Issue: Because this algorithm can be called from [=in parallel=] steps, parts of this and other algorithms are racy. Specifically, the - [=Scheduler/next enqueue order=] should be updated atomically, and accessing + [=event loop/next enqueue order=] should be updated atomically, and accessing the [=scheduler task queues=] should occur atomically. The latter also affects the event loop task queues (see [this issue](https://github.com/whatwg/html/issues/6475)).
@@ -323,35 +310,38 @@ see [whatwg/html#5925](https://github.com/whatwg/html/issues/5925).
To get the runnable task queues - for a {{Scheduler}} |scheduler|, run the following steps: + for a {{Scheduler}} |scheduler|: - 1. Let |queues| be the result of [=map/get the values|getting the values=] of - |scheduler|'s [=Scheduler/static priority task queue map=]. - 1. [=list/Extend=] |queues| with the result of [=map/get the values|getting the values=] - of |scheduler|'s [=Scheduler/dynamic priority task queue map=]. + 1. Let |queues| be the result of [=map/get the values|getting the values=] of |scheduler|'s + [=Scheduler/static priority task queue map=]. + 1. [=list/Extend=] |queues| with the result of [=map/get the values|getting the values=] of + |scheduler|'s [=Scheduler/dynamic priority task queue map=]. 1. [=list/Remove=] from |queues| any |queue| such that |queue|'s [=scheduler task queue/tasks=] do not contain a [=task/runnable=] [=scheduler task=]. 1. Return |queues|.
-
- The result of selecting the task queue of the next scheduler task - for {{Scheduler}} |scheduler| is a [=set=] of [=scheduler tasks=] as defined - by the following steps: +
+ To select the next scheduler queue from all schedulers given an [=event loop=] + |event loop|, perform the following steps. They return a [=scheduler task queue=] or null if no + {{Scheduler}} associated with the |event loop| [=has a runnable task=]. - 1. Let |queues| be the result of [=getting the runnable task queues=] for |scheduler|. + 1. Let |queues| be an empty [=set=]. + 1. Let |schedulers| be the [=set=] of all {{Scheduler}} objects whose [=relevant agent's=] + [=agent/event loop=] is |event loop| and that [=have a runnable task=]. + 1. For each |scheduler| in |schedulers|, [=list/extend=] |queues| with the result of [=getting the + runnable task queues=] for |scheduler|. 1. If |queues| is [=list/empty=] return null. 1. [=set/Remove=] from |queues| any |queue| such that |queue|'s [=scheduler task queue/priority=] is [=TaskPriority/less than=] any other [=set/item=] of |queues|. 1. Let |queue| be the [=scheduler task queue=] in |queues| whose - [=scheduler task queue/first runnable task=] is the - [=scheduler task/older than|oldest=]. + [=scheduler task queue/first runnable task=] is the [=scheduler task/older than|oldest=].
Two tasks cannot have the same age since [=scheduler task/enqueue order=] is unique. - 1. Return |queue|'s [=scheduler task queue/tasks=]. + 1. Return |queue|. Note: The next task to run is the oldest, highest priority [=task/runnable=] - [=scheduler task=]. + [=scheduler task=] from all {{Scheduler}}s associated with the [=event loop=].
Examples {#sec-scheduling-tasks-examples}