From 0985dde9d525605d85102059156465d353ce267c Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Wed, 17 Sep 2025 10:30:49 +0100 Subject: [PATCH 01/13] Clarify when details should go on events vs targets --- index.bs | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/index.bs b/index.bs index 2cc3ce42..5ec14282 100644 --- a/index.bs +++ b/index.bs @@ -1615,7 +1615,7 @@ Unlike dictionaries, interfaces: (i.e., one can check if it is an `instanceof` a particular class on the global scope), Defining an interface also exposes it on the global scope, allowing for the specification of static methods. -For example, the `canParse()` static method of the URL interface. +For example, the `canParse()` static method of the URL interface. ```JS if (URL.canParse(someURL)) { @@ -2554,12 +2554,30 @@ as it implies that it's possible to dispatch an event asynchronously. All events are dispatched synchronously. What is more often implied by "asynchronous event" is to defer firing an event. -

Use plain {{Event}}s for state

+

Put state on {{Event/target}} objects rather than {{Event}}s

-Where possible, use a plain {{Event}} with a specified `type`, -and capture any state information in the {{Event/target}} object. +Where possible, capture any state information in the {{Event/target}} object, +and use events with a specified `type` to signal updates to that state. -It's usually not necessary to create new subclasses of {{Event}}. +
+This means the {{Event/target}} object can used to determine the current state, +without waiting for the next \'change\' event. + +This is particularly useful if there's a final state, +where there will be no further \'change\' events. +
+ +It's usually not necessary to create new subclasses of {{Event}}, +but they can be used to provide information relating to how the state change occurred. + +
+Properties on {{HTMLInputElement}}, +such as {{HTMLInputElement/value}}, +provide the state of the input. +Properties on {{InputEvent}}, +such as {{InputEvent/inputType}}, +describe the nature of an update to the state. +

Use Events and Observers appropriately

From 9337eb6d3a178b009bdc59a15128960fae1ad22e Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Wed, 17 Sep 2025 10:38:11 +0100 Subject: [PATCH 02/13] Update index.bs --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 5ec14282..0f623aec 100644 --- a/index.bs +++ b/index.bs @@ -1615,7 +1615,7 @@ Unlike dictionaries, interfaces: (i.e., one can check if it is an `instanceof` a particular class on the global scope), Defining an interface also exposes it on the global scope, allowing for the specification of static methods. -For example, the `canParse()` static method of the URL interface. +For example, the `canParse()` static method of the URL interface. ```JS if (URL.canParse(someURL)) { From 1193cfa631b7bf8323a25c466cb9b415c2a65b20 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Wed, 17 Sep 2025 12:18:46 +0100 Subject: [PATCH 03/13] Provide counter-example --- index.bs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 0f623aec..a8faa48a 100644 --- a/index.bs +++ b/index.bs @@ -1615,7 +1615,7 @@ Unlike dictionaries, interfaces: (i.e., one can check if it is an `instanceof` a particular class on the global scope), Defining an interface also exposes it on the global scope, allowing for the specification of static methods. -For example, the `canParse()` static method of the URL interface. +For example, the `canParse()` static method of the URL interface. ```JS if (URL.canParse(someURL)) { @@ -2579,6 +2579,18 @@ such as {{InputEvent/inputType}}, describe the nature of an update to the state. +
+An example where this is handled inconsistently is {{XMLHttpRequest}}, +where some request state is on the {{XMLHttpRequest|target}}, +such as {{XMLHttpRequest/readyState}}. +Whereas other state, +such as {{ProgressEvent/lengthComputable}} and {{ProgressEvent/total}}, +are only available via a {{ProgressEvent}} object via a {{XMLHttpRequestEventTarget/progress}} event. + +If the developer gets access to the {{XMLHttpRequest}} object after the first {{XMLHttpRequestEventTarget/progress}} event, +the current {{ProgressEvent/lengthComputable}} and {{ProgressEvent/total}} values are inaccessible to them. +
+

Use Events and Observers appropriately

In general, use {{EventTarget}} and notification {{Event}}s, From 4c962eb61bc9e95ff147f295992f7b939599b465 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Wed, 17 Sep 2025 12:24:38 +0100 Subject: [PATCH 04/13] Tweaks --- index.bs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/index.bs b/index.bs index a8faa48a..79f51256 100644 --- a/index.bs +++ b/index.bs @@ -2581,14 +2581,17 @@ describe the nature of an update to the state.
An example where this is handled inconsistently is {{XMLHttpRequest}}, -where some request state is on the {{XMLHttpRequest|target}}, -such as {{XMLHttpRequest/readyState}}. +where some state is on the {{XMLHttpRequest|target}}, +such as {{XMLHttpRequest/readyState}} and {{XMLHttpRequest/status}}. Whereas other state, such as {{ProgressEvent/lengthComputable}} and {{ProgressEvent/total}}, -are only available via a {{ProgressEvent}} object via a {{XMLHttpRequestEventTarget/progress}} event. +is only available via a {{ProgressEvent}} object via a {{XMLHttpRequestEventTarget/progress}} event. If the developer gets access to the {{XMLHttpRequest}} object after the first {{XMLHttpRequestEventTarget/progress}} event, the current {{ProgressEvent/lengthComputable}} and {{ProgressEvent/total}} values are inaccessible to them. + +Instead, all state should have been on the {{XMLHttpRequest}} object, +and the {{XMLHttpRequestEventTarget/progress}} event should have been a simple {{Event}}.

Use Events and Observers appropriately

From 209d53320ef807ad4fd680f6d8be14f3adece500 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Wed, 17 Sep 2025 12:53:13 +0100 Subject: [PATCH 05/13] Grammar tweaks --- index.bs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/index.bs b/index.bs index 79f51256..02beafab 100644 --- a/index.bs +++ b/index.bs @@ -2580,12 +2580,12 @@ describe the nature of an update to the state.
-An example where this is handled inconsistently is {{XMLHttpRequest}}, -where some state is on the {{XMLHttpRequest|target}}, -such as {{XMLHttpRequest/readyState}} and {{XMLHttpRequest/status}}. -Whereas other state, +An example where this is handled inconsistently is {{XMLHttpRequest}}. +Some state is on the {{XMLHttpRequest|target}}, +such as {{XMLHttpRequest/readyState}} and {{XMLHttpRequest/status}}, +whereas other state, such as {{ProgressEvent/lengthComputable}} and {{ProgressEvent/total}}, -is only available via a {{ProgressEvent}} object via a {{XMLHttpRequestEventTarget/progress}} event. +is only available on {{ProgressEvent}} objects via a {{XMLHttpRequestEventTarget/progress}} event. If the developer gets access to the {{XMLHttpRequest}} object after the first {{XMLHttpRequestEventTarget/progress}} event, the current {{ProgressEvent/lengthComputable}} and {{ProgressEvent/total}} values are inaccessible to them. From 0d037b55013f0cc26f013c1e9b372f77d072bd3b Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Wed, 17 Sep 2025 12:57:22 +0100 Subject: [PATCH 06/13] Tweaks --- index.bs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.bs b/index.bs index 02beafab..2a2ce0d9 100644 --- a/index.bs +++ b/index.bs @@ -2556,15 +2556,15 @@ What is more often implied by "asynchronous event" is to defer firing an event.

Put state on {{Event/target}} objects rather than {{Event}}s

-Where possible, capture any state information in the {{Event/target}} object, -and use events with a specified `type` to signal updates to that state. +Where possible, rather than put state on {{Event}} objects, put state on the {{Event/target}} +and use events to signal updates to that state.
This means the {{Event/target}} object can used to determine the current state, -without waiting for the next \'change\' event. +without waiting for the next \'update\' event. This is particularly useful if there's a final state, -where there will be no further \'change\' events. +where there will be no further \'update\' events.
It's usually not necessary to create new subclasses of {{Event}}, From 0c3916fcd135aa2edd4e8ac05f128c5a07f374f1 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Thu, 18 Sep 2025 11:23:40 +0100 Subject: [PATCH 07/13] Apply suggestions from code review Co-authored-by: Martin Thomson --- index.bs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/index.bs b/index.bs index 2a2ce0d9..e2d9e722 100644 --- a/index.bs +++ b/index.bs @@ -2556,15 +2556,15 @@ What is more often implied by "asynchronous event" is to defer firing an event.

Put state on {{Event/target}} objects rather than {{Event}}s

-Where possible, rather than put state on {{Event}} objects, put state on the {{Event/target}} -and use events to signal updates to that state. +Put state on the {{Event/target}} +and use events to signal updates to that state, +rather than having state on {{Event}} objects.
-This means the {{Event/target}} object can used to determine the current state, -without waiting for the next \'update\' event. - +Having state on the {{Event/target}} object can used to determine the current state, +without waiting for the next event. This is particularly useful if there's a final state, -where there will be no further \'update\' events. +where there will be no further events.
It's usually not necessary to create new subclasses of {{Event}}, @@ -2579,19 +2579,13 @@ such as {{InputEvent/inputType}}, describe the nature of an update to the state.
-
-An example where this is handled inconsistently is {{XMLHttpRequest}}. -Some state is on the {{XMLHttpRequest|target}}, +
+An example where this is handled inconsistently is {{XMLHttpRequest}}, +where some state is on the {{XMLHttpRequest|target}}, such as {{XMLHttpRequest/readyState}} and {{XMLHttpRequest/status}}, -whereas other state, +and other state, such as {{ProgressEvent/lengthComputable}} and {{ProgressEvent/total}}, is only available on {{ProgressEvent}} objects via a {{XMLHttpRequestEventTarget/progress}} event. - -If the developer gets access to the {{XMLHttpRequest}} object after the first {{XMLHttpRequestEventTarget/progress}} event, -the current {{ProgressEvent/lengthComputable}} and {{ProgressEvent/total}} values are inaccessible to them. - -Instead, all state should have been on the {{XMLHttpRequest}} object, -and the {{XMLHttpRequestEventTarget/progress}} event should have been a simple {{Event}}.

Use Events and Observers appropriately

From 726b82fff2f82662958e163c5a83fd99549adcb6 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Thu, 18 Sep 2025 11:28:10 +0100 Subject: [PATCH 08/13] Remove counter-example --- index.bs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/index.bs b/index.bs index e2d9e722..321b9c0c 100644 --- a/index.bs +++ b/index.bs @@ -2579,15 +2579,6 @@ such as {{InputEvent/inputType}}, describe the nature of an update to the state.
-
-An example where this is handled inconsistently is {{XMLHttpRequest}}, -where some state is on the {{XMLHttpRequest|target}}, -such as {{XMLHttpRequest/readyState}} and {{XMLHttpRequest/status}}, -and other state, -such as {{ProgressEvent/lengthComputable}} and {{ProgressEvent/total}}, -is only available on {{ProgressEvent}} objects via a {{XMLHttpRequestEventTarget/progress}} event. -
-

Use Events and Observers appropriately

In general, use {{EventTarget}} and notification {{Event}}s, From 3459c82e7cb4d862acf6f341113adb5aa3caa5d7 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Thu, 18 Sep 2025 15:43:47 +0100 Subject: [PATCH 09/13] Document exception case --- index.bs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/index.bs b/index.bs index 332969b5..66a6a2db 100644 --- a/index.bs +++ b/index.bs @@ -2581,6 +2581,13 @@ such as {{InputEvent/inputType}}, describe the nature of an update to the state. +In some exceptional cases, where maintaining state on an object is expensive, +the state may be placed on the {{Event}} instances, +allowing {{EventTarget/addEventListener}} and {{EventTarget/removeEventListener}} to signal interest/disinterest in this state. +Although, other patterns should be considered, +such as retuning an {{EventTarget}} from a function, +where the function call is a similar signal of interest. +

Use Events and Observers appropriately

In general, use {{EventTarget}} and notification {{Event}}s, From 3bc1e5999919c32a20096615d94c702770ead986 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Tue, 21 Oct 2025 09:06:06 +0100 Subject: [PATCH 10/13] Add example --- index.bs | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/index.bs b/index.bs index 66a6a2db..d90d80ac 100644 --- a/index.bs +++ b/index.bs @@ -2582,11 +2582,35 @@ describe the nature of an update to the state. In some exceptional cases, where maintaining state on an object is expensive, -the state may be placed on the {{Event}} instances, -allowing {{EventTarget/addEventListener}} and {{EventTarget/removeEventListener}} to signal interest/disinterest in this state. -Although, other patterns should be considered, -such as retuning an {{EventTarget}} from a function, -where the function call is a similar signal of interest. +other patterns may be considered, +such as returning an {{EventTarget}} from a function call, +where the function call is a signal of interest. + +
+ Using an imaginary `dataUsage` API that reports the amount of data an environment has used, the recommended pattern is: + +
+self.dataUsage.addEventListener('change', () => {
+  console.log(self.dataUsage.bytesReceived);
+});
+  
+ + Where `bytesReceived` exists on the `dataUsage` {{EventTarget}}, + rather than the {{Event}}. + + If updating the state on this object is too expensive, this pattern may be considered: + +
+const dataUsage = await self.monitorDataUsage();
+
+dataUsage.addEventListener('change', () => {
+  console.log(dataUsage.bytesReceived);
+});
+  
+ + In this pattern, the call to `monitorDataUsage` signals interest in the data, + and the state does not need to be updated until `monitorDataUsage` is called. +

Use Events and Observers appropriately

From 6debdb7f3b2cee18dcd658ce9ee93491176cc0ec Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Tue, 21 Oct 2025 13:44:44 +0100 Subject: [PATCH 11/13] Update index.bs Co-authored-by: Martin Thomson --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 3f4210f9..fed01b5f 100644 --- a/index.bs +++ b/index.bs @@ -2627,7 +2627,7 @@ self.dataUsage.addEventListener('change', () => { Where `bytesReceived` exists on the `dataUsage` {{EventTarget}}, rather than the {{Event}}. - If updating the state on this object is too expensive, this pattern may be considered: + If maintaining the state on this object is too expensive, this pattern may be considered:
 const dataUsage = await self.monitorDataUsage();

From 20d746794e5920a515f529b16b0f00962454bafd Mon Sep 17 00:00:00 2001
From: Jake Archibald 
Date: Wed, 22 Oct 2025 11:15:31 +0100
Subject: [PATCH 12/13] Apply suggestion from @martinthomson

Co-authored-by: Martin Thomson 
---
 index.bs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/index.bs b/index.bs
index fed01b5f..a097208c 100644
--- a/index.bs
+++ b/index.bs
@@ -2591,7 +2591,6 @@ Put state on the {{Event/target}}
 and use events to signal updates to that state,
 rather than having state on {{Event}} objects.
 
-
Having state on the {{Event/target}} object can used to determine the current state, without waiting for the next event. This is particularly useful if there's a final state, From fb77d035a82831402593238d5d0da37797b9c2f9 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Wed, 22 Oct 2025 11:15:39 +0100 Subject: [PATCH 13/13] Apply suggestion from @martinthomson Co-authored-by: Martin Thomson --- index.bs | 1 - 1 file changed, 1 deletion(-) diff --git a/index.bs b/index.bs index a097208c..386e03b4 100644 --- a/index.bs +++ b/index.bs @@ -2595,7 +2595,6 @@ Having state on the {{Event/target}} object can used to determine the current st without waiting for the next event. This is particularly useful if there's a final state, where there will be no further events. -
It's usually not necessary to create new subclasses of {{Event}}, but they can be used to provide information relating to how the state change occurred.