diff --git a/spec/controlling-tasks.md b/spec/controlling-tasks.md index 115b662..734f31f 100644 --- a/spec/controlling-tasks.md +++ b/spec/controlling-tasks.md @@ -1,15 +1,12 @@ -Controlling Tasks {#sec-controlling-tasks} -===================== +# Controlling Tasks # {#sec-controlling-tasks} -Tasks scheduled through the {{Scheduler}} interface can be controlled with a -{{TaskController}} by passing the {{TaskSignal}} provided by -{{AbortController/signal|controller.signal}} as the -{{SchedulerPostTaskOptions/signal|option}} when calling {{Scheduler/postTask()}}. -The {{TaskController}} interface supports aborting and changing the priority of -a task or group of tasks. +Tasks scheduled through the {{Scheduler}} interface can be controlled with a {{TaskController}} by +passing the {{TaskSignal}} provided by {{AbortController/signal|controller.signal}} as the +{{SchedulerPostTaskOptions/signal|option}} when calling {{Scheduler/postTask()}}. The +{{TaskController}} interface supports aborting and changing the priority of a task or group of +tasks. -The `TaskPriorityChangeEvent` Interface {#sec-task-priority-change-event} ---------------------- +## The `TaskPriorityChangeEvent` Interface ## {#sec-task-priority-change-event}
[Exposed=(Window, Worker)] @@ -27,19 +24,17 @@ The `TaskPriorityChangeEvent` Interface {#sec-task-priority-change-event}
event . {{TaskPriorityChangeEvent/previousPriority}}
Returns the {{TaskPriority}} of the corresponding {{TaskSignal}} prior to - this `prioritychange` event. +
Returns the {{TaskPriority}} of the corresponding {{TaskSignal}} prior to this + `prioritychange` event.
The new {{TaskPriority}} can be read with `event.target.priority`.
dictionary TaskControllerInit { @@ -54,22 +49,21 @@ The `TaskController` Interface {#sec-task-controller} };-Note: {{TaskController}}'s {{AbortController/signal}} getter, which is -inherited from {{AbortController}}, returns a {{TaskSignal}} object. +Note: {{TaskController}}'s {{AbortController/signal}} getter, which is inherited from +{{AbortController}}, returns a {{TaskSignal}} object.
controller = new {{TaskController/TaskController()|TaskController}}( |init| )
Returns a new {{TaskController}} whose {{AbortController/signal}} is - set to a newly created {{TaskSignal}} with its {{TaskSignal/priority}} - initialized to |init|'s {{TaskControllerInit/priority}}. +
Returns a new {{TaskController}} whose {{AbortController/signal}} is set to a newly created + {{TaskSignal}} with its {{TaskSignal/priority}} initialized to |init|'s + {{TaskControllerInit/priority}}.
controller . {{TaskController/setPriority()|setPriority}}( |priority| )
Invoking this method will change the associated {{TaskSignal}}'s - [=TaskSignal/priority=], signal the priority change to any observers, and - cause `prioritychange` events to be dispatched. +
Invoking this method will change the associated {{TaskSignal}}'s [=TaskSignal/priority=], + signal the priority change to any observers, and cause `prioritychange` events to be dispatched.
setPriority(|priority|)
-method steps are to [=TaskSignal/signal priority change=] on [=this=]'s
-[=AbortController/signal=] given |priority|.
+The setPriority(|priority|)
method steps are to
+[=TaskSignal/signal priority change=] on [=this=]'s [=AbortController/signal=] given |priority|.
-The `TaskSignal` Interface {#sec-task-signal}
----------------------
+## The `TaskSignal` Interface ## {#sec-task-signal}
dictionary TaskSignalAnyInit { @@ -104,9 +96,9 @@ The `TaskSignal` Interface {#sec-task-signal} };-Note: {{TaskSignal}} inherits from {{AbortSignal}} and can be used in APIs that -accept an {{AbortSignal}}. Additionally, {{Scheduler/postTask()}} accepts an -{{AbortSignal}}, which can be useful if dynamic prioritization is not needed. +Note: {{TaskSignal}} inherits from {{AbortSignal}} and can be used in APIs that accept an +{{AbortSignal}}. Additionally, {{Scheduler/postTask()}} accepts an {{AbortSignal}}, which can be +useful if dynamic prioritization is not needed.
TaskSignal . any(|signals|, |init|)
@@ -137,30 +129,32 @@ A {{TaskSignal}} object has associated dependent signalsdependent (a
-boolean), which is initially false.
+A {{TaskSignal}} object has an associated dependent (a boolean), which is
+initially false.
-onprioritychange
attribute
-is an [=event handler IDL attribute=] for the `onprioritychange`
-[=event handler=], whose [=event handler event type=] is
-prioritychange.
+The onprioritychange
attribute is an [=event
+handler IDL attribute=] for the `onprioritychange` [=event handler=], whose [=event handler event
+type=] is prioritychange.
-To add a priority change algorithm |algorithm| to a
-{{TaskSignal}} object |signal|, [=set/append=] |algorithm| to |signal|'s
-[=TaskSignal/priority change algorithms=].
+The static any(|signals|, |init|)
method steps are to
+return the result of [=creating a dependent task signal=] from |signals| and |init|.
-any(|signals|, |init|)
method steps are:
+ To create a dependent task signal from a [=list=] of {{AbortSignal}} objects |signals|
+ and a {{TaskSignalAnyInit}} |init|:
1. Let |resultSignal| be the result of creating a dependent signal from
|signals| using the {{TaskSignal}} interface and the [=current realm=].
@@ -180,8 +174,8 @@ if it is a [=TaskSignal/dependent=] signal with a null [=TaskSignal/source signa
diff --git a/spec/introduction.md b/spec/introduction.md index 57fc991..a5a7fe1 100644 --- a/spec/introduction.md +++ b/spec/introduction.md @@ -1,5 +1,4 @@ -Introduction {#intro} -===================== +# Introduction # {#intro}diff --git a/spec/patches.md b/spec/patches.md index c855ba8..6b990b5 100644 --- a/spec/patches.md +++ b/spec/patches.md @@ -1,14 +1,11 @@ -Modifications to Other Standards {#sec-patches} -===================== +# Modifications to Other Standards # {#sec-patches} -The HTML Standard {#sec-patches-html} ---------------------- +## The HTML Standard ## {#sec-patches-html} ### `WindowOrWorkerGlobalScope` ### {#sec-patches-html-windoworworkerglobalscope} -Each object implementing the {{WindowOrWorkerGlobalScope}} mixin has a -corresponding scheduler, which -is initialized as a new {{Scheduler}}. +Each object implementing the {{WindowOrWorkerGlobalScope}} mixin has a corresponding +scheduler, which is initialized as a new {{Scheduler}}.partial interface mixin WindowOrWorkerGlobalScope { @@ -16,43 +13,38 @@ is initialized as a new {{Scheduler}}. };-The scheduler attribute's -getter steps are to return [=this=]'s [=WindowOrWorkerGlobalScope/scheduler=]. - +The scheduler attribute's getter steps are to +return [=this=]'s [=WindowOrWorkerGlobalScope/scheduler=]. ### Event loop: definitions ### {#sec-patches-html-event-loop-definitions} -Replace: For each [=event loop=], every [=task source=] must be associated with -a specific [=task queue=]. +Replace: For each [=event loop=], every [=task source=] must be associated with 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=]. +With: For each [=event loop=], every [=task source=] that is not a [=scheduler task source=] must be +associated with a specific [=task queue=]. ### 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. + 1. Let |queues| be the [=set=] of the [=event loop=]'s [=task queues=] that contain at least one + [=task/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 themicrotasks
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. - -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 -[=set/item=], so they are *roughly* compatible. Ideally, there would be a -common task queue interface that supports a `pop()` method that would return a -plain [=task=], but that would invlove a fair amount of refactoring. + 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. + +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 [=set/item=], so they are +*roughly* compatible. Ideally, there would be a common task queue interface that supports a `pop()` +method that would return a plain [=task=], but that would involve a fair amount of refactoring. diff --git a/spec/privacy.md b/spec/privacy.md index 7cada1e..0be3fee 100644 --- a/spec/privacy.md +++ b/spec/privacy.md @@ -1,5 +1,4 @@ -Privacy Considerations {#sec-privacy} -===================== +# Privacy Considerations # {#sec-privacy}diff --git a/spec/scheduling-tasks.md b/spec/scheduling-tasks.md index 922b311..7a7ec89 100644 --- a/spec/scheduling-tasks.md +++ b/spec/scheduling-tasks.md @@ -1,8 +1,6 @@ -Scheduling Tasks {#sec-scheduling-tasks} -===================== +# Scheduling Tasks # {#sec-scheduling-tasks} -Task Priorities {#sec-task-priorities} ---------------------- +## Task Priorities ## {#sec-task-priorities} This spec formalizes three priorities to support scheduling tasks: @@ -14,24 +12,22 @@ This spec formalizes three priorities to support scheduling tasks: }; -user-blocking is the highest priority, -and is meant to be used for tasks that are blocking the user's ability to -interact with the page, such as rendering the core experience or responding to -user input. +user-blocking is the highest priority, and is meant to be +used for tasks that are blocking the user's ability to interact with the page, such as rendering the +core experience or responding to user input. -user-visible is the second highest -priority, and is meant to be used for tasks that visible to the user but not -necessarily blocking user actions, such as rendering secondary parts of the -page. This is the default priority. +user-visible is the second highest priority, and is meant to +be used for tasks that visible to the user but not necessarily blocking user actions, such as +rendering secondary parts of the page. This is the default priority. -background is the lowest priority, and -is meant to be used for tasks that are not time-critical, such as background -log processing or initializing certain third party libraries. +background is the lowest priority, and is meant to be used +for tasks that are not time-critical, such as background log processing or initializing certain +third party libraries. -Note: Tasks scheduled through a given {{Scheduler}} run in *strict priority -order*, meaning the scheduler will always run "{{TaskPriority/user-blocking}}" -tasks before "{{TaskPriority/user-visible}}" tasks, which in turn always run -before "{{TaskPriority/background}}" tasks. +Note: Tasks scheduled through a given {{Scheduler}} run in *strict priority order*, meaning the +scheduler will always run "{{TaskPriority/user-blocking}}" tasks before +"{{TaskPriority/user-visible}}" tasks, which in turn always run before "{{TaskPriority/background}}" +tasks.{{TaskPriority}} |p1| is less than @@ -41,8 +37,7 @@ before "{{TaskPriority/background}}" tasks.-The `Scheduler` Interface {#sec-scheduler} ---------------------- +## The `Scheduler` Interface ## {#sec-scheduler}dictionary SchedulerPostTaskOptions { @@ -60,112 +55,96 @@ The `Scheduler` Interface {#sec-scheduler} }; -Note: The {{SchedulerPostTaskOptions/signal}} option can be either an -{{AbortSignal}} or a {{TaskSignal}}, but is defined as an {{AbortSignal}} since -it is a superclass of {{TaskSignal}}. For cases where the priority might -change, a {{TaskSignal}} is needed. But for cases where only cancellation is -needed, an {{AbortSignal}} would suffice, potentially making it easier to -integrate the API into existing code that uses {{AbortSignal|AbortSignals}}. +Note: The {{SchedulerPostTaskOptions/signal}} option can be either an {{AbortSignal}} or a +{{TaskSignal}}, but is defined as an {{AbortSignal}} since it is a superclass of {{TaskSignal}}. For +cases where the priority might change, a {{TaskSignal}} is needed. But for cases where only +cancellation is needed, an {{AbortSignal}} would suffice, potentially making it easier to integrate +the API into existing code that uses {{AbortSignal|AbortSignals}}.A {{Scheduler}} object has an associated static priority task queue map, -which is a [=map=] from {{TaskPriority}} to [=scheduler task queue=]. This map -is initialized to a new empty [=map=]. +which is a [=map=] from {{TaskPriority}} to [=scheduler task queue=]. This map is initialized to a +new empty [=map=]. A {{Scheduler}} object has an associated dynamic priority task queue map, -which is a [=map=] from {{TaskSignal}} to [=scheduler task queue=]. This map is -initialized to a new empty [=map=]. - -Note: We implement *dynamic prioritization* by enqueuing tasks associated with -a specific {{TaskSignal}} into the same [=scheduler task queue=], and changing -that queue's priority in response to `prioritychange` events. The -[=Scheduler/dynamic priority task queue map=] holds the -[=scheduler task queues=] whose priorities can change, and the map key is the -{{TaskSignal}} which all tasks in the queue are associated with. +which is a [=map=] from {{TaskSignal}} to [=scheduler task queue=]. This map is initialized to a new +empty [=map=]. + +Note: We implement *dynamic prioritization* by enqueuing tasks associated with a specific +{{TaskSignal}} into the same [=scheduler task queue=], and changing that queue's priority in +response to `prioritychange` events. The [=Scheduler/dynamic priority task queue map=] holds the +[=scheduler task queues=] whose priorities can change, and the map key is the {{TaskSignal}} which +all tasks in the queue are associated with.
result = scheduler . {{Scheduler/postTask()|postTask}}( |callback|, |options| )
- -
Returns a promise that is fulfilled with the return value of |callback|, - or rejected with the {{AbortSignal}}'s [=AbortSignal/abort reason=] if the - task is aborted. If |callback| throws an error during execution, the promise - returned by {{Scheduler/postTask()}} will be rejected with that error. +
Returns a promise that is fulfilled with the return value of |callback|, or rejected with the + {{AbortSignal}}'s [=AbortSignal/abort reason=] if the task is aborted. If |callback| throws an + error during execution, the promise returned by {{Scheduler/postTask()}} will be rejected with + that error. -
The task's {{TaskPriority|priority}} is determined by the combination of - |option|'s {{SchedulerPostTaskOptions/priority}} and - {{SchedulerPostTaskOptions/signal}}: +
The task's {{TaskPriority|priority}} is determined by the combination of |option|'s + {{SchedulerPostTaskOptions/priority}} and {{SchedulerPostTaskOptions/signal}}:
-
+- If |option|'s {{SchedulerPostTaskOptions/priority}} is specified, then - that {{TaskPriority}} will be used to schedule the task, and the task's - priority is immutable.
+If |option|'s {{SchedulerPostTaskOptions/priority}} is specified, then that + {{TaskPriority}} will be used to schedule the task, and the task's priority is immutable. -
- Otherwise, if |option|'s {{SchedulerPostTaskOptions/signal}} is - specified and is a {{TaskSignal}} object, then the task's priority is - determined by |option|'s {{SchedulerPostTaskOptions/signal}}'s - [=TaskSignal/priority=]. In this case the task's priority is *dynamic*, - and can be changed by calling {{TaskController/setPriority()|controller.setPriority()}} - for the associated {{TaskController}}.
+Otherwise, if |option|'s {{SchedulerPostTaskOptions/signal}} is specified and is a + {{TaskSignal}} object, then the task's priority is determined by |option|'s + {{SchedulerPostTaskOptions/signal}}'s [=TaskSignal/priority=]. In this case the task's + priority is *dynamic*, and can be changed by calling + {{TaskController/setPriority()|controller.setPriority()}} for the associated + {{TaskController}}. -
- Otherwise, the task's priority defaults to "{{TaskPriority/user-visible}}".
-Otherwise, the task's priority defaults to "{{TaskPriority/user-visible}}". +
If |option|'s {{SchedulerPostTaskOptions/signal}} is specified, then the - {{SchedulerPostTaskOptions/signal}} is used by the {{Scheduler}} to - determine if the task is aborted. + {{SchedulerPostTaskOptions/signal}} is used by the {{Scheduler}} to determine if the task is + aborted. -
If |option|'s {{SchedulerPostTaskOptions/delay}} is specified and greater - than 0, then the execution of the task will be delayed for at least - {{SchedulerPostTaskOptions/delay}} milliseconds. +
If |option|'s {{SchedulerPostTaskOptions/delay}} is specified and greater than 0, then the + execution of the task will be delayed for at least {{SchedulerPostTaskOptions/delay}} + milliseconds.
-The values of the [=Scheduler/static priority task queue map=] are -[=scheduler task queues=] whose priorities do not change. Tasks with *static -priorities* — those that were scheduled with an explicit -{{SchedulerPostTaskOptions/priority}} option or a -{{SchedulerPostTaskOptions/signal}} option that is null or is an {{AbortSignal}} -— are placed in these queues, based on {{TaskPriority}}, which is the -key for the map. +The values of the [=Scheduler/static priority task queue map=] are [=scheduler task queues=] whose +priorities do not change. Tasks with *static priorities* — those that were scheduled with an +explicit {{SchedulerPostTaskOptions/priority}} option or a {{SchedulerPostTaskOptions/signal}} +option that is null or is an {{AbortSignal}} — are placed in these queues, based on +{{TaskPriority}}, which is the key for the map.
-An alternative, and logicially equivalent implementation, would be to maintain a -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 -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 +An alternative, and logicially equivalent implementation, would be to maintain a 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 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|. +method steps are to return the result of [=scheduling a postTask task=] for [=this=] given +|callback| and |options|. -Definitions {#sec-scheduling-tasks-definitions} ---------------------- +## Definitions ## {#sec-scheduling-tasks-definitions} A scheduler task is a [=/task=] with an additional numeric enqueue order [=struct/item=], initially set to 0. -A [=scheduler task=] |t1| is older than -[=scheduler task=] |t2| if |t1|'s [=scheduler task/enqueue order=] less than |t2|'s -[=scheduler task/enqueue order=]. - -
- The following [=task sources=] are defined as scheduler task sources, and must only be used for [=scheduler tasks=]. @@ -181,9 +160,16 @@ A scheduler task queue is a [=struct=] with the following [=struct/it : tasks :: A [=set=] of [=scheduler tasks=]. + +## Processing Model ## {#sec-scheduling-tasks-processing-model} + ++ A [=scheduler task=] |t1| is older than [=scheduler task=] |t2| if + |t1|'s [=scheduler task/enqueue order=] less than |t2|'s [=scheduler task/enqueue order=]. ++- To create a scheduler task queue - with {{TaskPriority}} |priority|: + To create a scheduler task queue with {{TaskPriority}} |priority|: 1. Let |queue| be a new [=scheduler task queue=]. 1. Set |queue|'s [=scheduler task queue/priority=] to |priority|. @@ -191,173 +177,153 @@ A scheduler task queue is a [=struct=] with the following [=struct/it 1. Return |queue|.-A [=scheduler task queue=] |queue|'s first runnable task -is the first [=scheduler task=] in |queue|'s [=scheduler task queue/tasks=] that is -[=task/runnable=]. - -Processing Model {#sec-scheduling-tasks-processing-model} ---------------------- ++ A [=scheduler task queue=] |queue|'s first runnable task is + the first [=scheduler task=] in |queue|'s [=scheduler task queue/tasks=] that is + [=task/runnable=]. +### Queueing and Removing Scheduler Tasks ### {#sec-queuing-scheduler-tasks} -- To queue a scheduler task - on a [=scheduler task queue=] |queue|, which performs a series of steps |steps|, - given a numeric |enqueue order|, a [=task source=] |source|, and a [=document=] |document|: ++ To queue a scheduler task on a [=scheduler task queue=] |queue|, which performs a + series of steps |steps|, given a numeric |enqueue order|, a [=task source=] |source|, and a + [=document=] |document|: 1. Let |task| be a new [=scheduler task=]. 1. Set |task|'s [=scheduler task/enqueue order=] to |enqueue order|. 1. Set |task|'s steps to |steps|. 1. Set |task|'s source to |source|. 1. Set |task|'s document to |document|. - 1. Set |task|'s script evaluation environment settings - object set to a new empty [=set=]. + 1. Set |task|'s script evaluation environment settings object set to a + new empty [=set=]. 1. [=set/Append=] |task| to |queue|'s [=scheduler task queue/tasks=]. 1. Return |task|. - Issue: We should consider refactoring the HTML spec to add a constructor for - [=/task=]. One problem is we need the new task to be a [=scheduler task=] - rather than a [=/task=]. + Issue: We should consider refactoring the HTML spec to add a constructor for [=/task=]. One + problem is we need the new task to be a [=scheduler task=] rather than a [=/task=].- To remove a [=scheduler task=] |task| from - [=scheduler task queue=] |queue|, [=set/remove=] |task| from |queue|'s - [=scheduler task queue/tasks=]. + To remove a [=scheduler task=] |task| from [=scheduler task + queue=] |queue|, [=set/remove=] |task| from |queue|'s [=scheduler task queue/tasks=].### Scheduling Tasks ### {#sec-scheduler-alg-scheduling-tasks} -- To schedule a postTask task - for {{Scheduler}} |scheduler| given a {{SchedulerPostTaskCallback}} |callback| and - {{SchedulerPostTaskOptions}} |options|, run the following steps: ++ To schedule a postTask task for {{Scheduler}} |scheduler| given a + {{SchedulerPostTaskCallback}} |callback| and {{SchedulerPostTaskOptions}} |options|: 1. Let |result| be [=a new promise=]. 1. Let |signal| be |options|["{{SchedulerPostTaskOptions/signal}}"] if - |options|["{{SchedulerPostTaskOptions/signal}}"] [=map/exists=], or - otherwise null. - 1. If |signal| is not null and it is [=AbortSignal/aborted=], then - [=reject=] |result| with |signal|'s [=AbortSignal/abort reason=] and return - |result|. + |options|["{{SchedulerPostTaskOptions/signal}}"] [=map/exists=], or otherwise null. + 1. If |signal| is not null and it is [=AbortSignal/aborted=], then [=reject=] |result| with + |signal|'s [=AbortSignal/abort reason=] and return |result|. 1. Let |priority| be |options|["{{SchedulerPostTaskOptions/priority}}"] if - |options|["{{SchedulerPostTaskOptions/priority}}"] [=map/exists=], or - otherwise null. - 1. Let |queue| be the result of [=selecting the scheduler task queue=] for - |scheduler| given |signal| and |priority|. + |options|["{{SchedulerPostTaskOptions/priority}}"] [=map/exists=], or otherwise null. + 1. Let |queue| be the result of [=selecting the scheduler task queue=] for |scheduler| given + |signal| and |priority|. 1. Let |delay| be |options|["{{SchedulerPostTaskOptions/delay}}"]. - 1. If |delay| is greater than 0, then [=run steps after a timeout=] given - |scheduler|'s [=relevant global object=], "`scheduler-postTask`", - |delay|, and the following steps: - 1. [=Schedule a task to invoke a callback=] for |scheduler| given |queue|, - |signal|, |callback|, and |result|. - 1. Otherwise, [=schedule a task to invoke a callback=] for |scheduler| given - |queue|, |signal|, |callback|, and |result|. + 1. If |delay| is greater than 0, then [=run steps after a timeout=] given |scheduler|'s [=relevant + global object=], "`scheduler-postTask`", |delay|, and the following steps: + 1. [=Schedule a task to invoke a callback=] for |scheduler| given |queue|, |signal|, |callback|, + and |result|. + 1. Otherwise, [=schedule a task to invoke a callback=] for |scheduler| given |queue|, |signal|, + |callback|, and |result|. 1. Return |result|.-Issue: [=Run steps after a timeout=] doesn't necessarily account for suspension; -see [whatwg/html#5925](https://github.com/whatwg/html/issues/5925). +Issue: [=Run steps after a timeout=] doesn't necessarily account for suspension; see +[whatwg/html#5925](https://github.com/whatwg/html/issues/5925). -- To select the scheduler task queue - for a {{Scheduler}} |scheduler| given an {{AbortSignal}} or null |signal|, and - a {{TaskPriority}} or null |priority|: ++ To select the scheduler task queue for a {{Scheduler}} |scheduler| given an + {{AbortSignal}} or null |signal|, and a {{TaskPriority}} or null |priority|: 1. If |priority| is null, |signal| is not null and [=implements=] the {{TaskSignal}} interface, and |signal| [=TaskSignal/has fixed priority=], then set |priority| to |signal|'s [=TaskSignal/priority=]. 1. If |priority| is null and |signal| is not null and [=implements=] the {{TaskSignal}} interface, then - 1. If |scheduler|'s [=Scheduler/dynamic priority task queue map=] does not - [=map/contain=] |signal|, then - 1. Let |queue| be the result of [=creating a scheduler task queue=] given - |signal|'s [=TaskSignal/priority=]. + 1. If |scheduler|'s [=Scheduler/dynamic priority task queue map=] does not [=map/contain=] + |signal|, then + 1. Let |queue| be the result of [=creating a scheduler task queue=] given |signal|'s + [=TaskSignal/priority=]. 1. Set [=Scheduler/dynamic priority task queue map=][|signal|] to |queue|. - 1. [=TaskSignal/Add a priority change algorithm=] to |signal| that - runs the following steps: - 1. Set |queue|'s [=scheduler task queue/priority=] to |signal|'s - {{TaskSignal/priority}}. + 1. [=TaskSignal/Add a priority change algorithm=] to |signal| that runs the following steps: + 1. Set |queue|'s [=scheduler task queue/priority=] to |signal|'s {{TaskSignal/priority}}. 1. Return [=Scheduler/dynamic priority task queue map=][|signal|]. 1. Otherwise |priority| is used to determine the task queue: 1. If |priority| is null, set |priority| to "{{TaskPriority/user-visible}}". - 1. If |scheduler|'s [=Scheduler/static priority task queue map=] does not - [=map/contain=] |priority|, then - 1. Let |queue| be the result of [=creating a scheduler task queue=] given - |priority|. + 1. If |scheduler|'s [=Scheduler/static priority task queue map=] does not [=map/contain=] + |priority|, then + 1. Let |queue| be the result of [=creating a scheduler task queue=] given |priority|. 1. Set [=Scheduler/static priority task queue map=][|priority|] to |queue|. 1. Return [=Scheduler/static priority task queue map=][|priority|].- To schedule a task to invoke a callback for {{Scheduler}} - |scheduler| given a [=scheduler task queue=] |queue|, an {{AbortSignal}} or - null |signal|, a SchedulerPostTaskCallback |callback|, and a promise |result|: + To schedule a task to invoke a callback for {{Scheduler}} |scheduler| given a + [=scheduler task queue=] |queue|, an {{AbortSignal}} or null |signal|, a SchedulerPostTaskCallback + |callback|, and a promise |result|: 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 |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 |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: - 1. Let |callback result| be the result of [=invoking=] |callback|. If that - threw an exception, then [=reject=] |result| with that, otherwise resolve - |result| with |callback result|. - 1. If |signal| is not null, then [=AbortSignal/add|add the following=] abort - steps to it: + 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: + 1. Let |callback result| be the result of [=invoking=] |callback|. If that threw an exception, + then [=reject=] |result| with that, otherwise resolve |result| with |callback result|. + 1. If |signal| is not null, then [=AbortSignal/add|add the following=] abort steps to it: 1. [=scheduler task queue/Remove=] |task| from |queue|. 1. [=Reject=] |result| with |signal|'s [=AbortSignal/abort reason=]. - 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 - 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)). + 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 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)).### Selecting the Next Task to Run ### {#sec-scheduler-alg-select-next-task} -- A {{Scheduler}} |scheduler| has a runnable task - if the result of [=getting the runnable task queues=] for |scheduler| is non-[=list/empty=]. ++ A {{Scheduler}} |scheduler| has a runnable + task if the result of [=getting the runnable task queues=] for |scheduler| is + non-[=list/empty=].-- To get the runnable task queues - for a {{Scheduler}} |scheduler|, run the following steps: - - 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=]. ++ To get the runnable task queues 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. [=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: + 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: 1. Let |queues| be 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=]. + 1. Let |queue| be the [=scheduler task queue=] in |queues| whose [=scheduler task queue/first + runnable task=] is the [=scheduler task/older than|oldest=].-Examples {#sec-scheduling-tasks-examples} ---------------------- +## Examples ## {#sec-scheduling-tasks-examples} **TODO**(shaseley): Add examples. diff --git a/spec/security.md b/spec/security.md index 8d20ab9..23d3c54 100644 --- a/spec/security.md +++ b/spec/security.md @@ -1,5 +1,4 @@ -Security Considerations {#sec-security} -===================== +# Security Considerations # {#sec-security}
Two tasks cannot have the same age since [=scheduler task/enqueue order=] is unique. 1. Return |queue|'s [=scheduler task queue/tasks=]. - Note: The next task to run is the oldest, highest priority [=task/runnable=] - [=scheduler task=]. + Note: The next task to run is the oldest, highest priority [=task/runnable=] [=scheduler task=].*This section is non-normative.* @@ -9,8 +8,7 @@ whether or not any information is potentially leaked between origins by timing-based side-channel attacks.-`postTask` as a High-Resolution Timing Source {#sec-security-high-res-timer} ---------------------- +## `postTask` as a High-Resolution Timing Source ## {#sec-security-high-res-timer}This API cannot be used as a high-resolution timing source. Like @@ -22,8 +20,7 @@ their delay expires and not run instantly, the precision available to callers is further reduced.-Monitoring Another Origin's Tasks {#sec-security-monitoring-tasks} ---------------------- +## Monitoring Another Origin's Tasks ## {#sec-security-monitoring-tasks}The second consideration is whether {{Scheduler/postTask()}} leaks any