@@ -36,7 +36,7 @@ urlPrefix: https://dom.spec.whatwg.org; spec: DOM
3636      text: signal; url: event-listener-signal
3737    for: AbortSignal
3838      text: dependent signals; url: abortsignal-dependent-signals
39-       text: signal abort
39+       text: signal abort; url:abortsignal-signal-abort 
4040</pre> 
4141
4242<style> 
@@ -175,15 +175,9 @@ observer/complete steps=].
175175Each {{Subscriber}}  has a <dfn for=Subscriber>teardown callbacks</dfn> , which is a [=list=]  of
176176{{VoidFunction}} s, initially empty.
177177
178- Each {{Subscriber}}  has a <dfn for=Subscriber>complete or error  controller</dfn> , which is an
178+ Each {{Subscriber}}  has a <dfn for=Subscriber>subscription  controller</dfn> , which is an
179179{{AbortController}} .
180180
181- Each {{Subscriber}}  has a <dfn for=Subscriber>signal</dfn> , which is an {{AbortSignal}} .
182- 
183- Note: This is a [=create a dependent abort signal|dependent signal=] , derived from both
184- [=Subscriber/complete or error controller=] 's [=AbortController/signal=] , and
185- {{SubscribeOptions}} 's {{SubscribeOptions/signal}}  (if non-null).
186- 
187181Each {{Subscriber}}  has a <dfn for=Subscriber>active</dfn>  boolean, initially true.
188182
189183Note: This is a bookkeeping variable to ensure that a {{Subscriber}}  never calls any of the
@@ -193,7 +187,7 @@ The <dfn attribute for=Subscriber><code>active</code></dfn> getter steps are to
193187[=Subscriber/active=]  boolean.
194188
195189The <dfn attribute for=Subscriber><code>signal</code></dfn>  getter steps are to return [=this=] 's
196- [=Subscriber/signal=] .
190+ [=Subscriber/subscription controller=]  's  [=AbortController/ signal=] .
197191
198192<div algorithm> 
199193  The <dfn for=Subscriber method><code>next(|value|)</code></dfn>  method steps are:
@@ -228,8 +222,6 @@ The <dfn attribute for=Subscriber><code>signal</code></dfn> getter steps are to
228222
229223    1. [=close a subscription|Close=]  [=this=] .
230224
231-     1. [=AbortController/Signal abort=]  [=this=] 's [=Subscriber/complete or error controller=] .
232- 
233225    1. Run [=this=] 's [=Subscriber/error algorithm=]  given |error|.
234226
235227       [=Assert=] : No <a spec=webidl lt="an exception was thrown">exception was thrown</a> .
@@ -247,8 +239,6 @@ The <dfn attribute for=Subscriber><code>signal</code></dfn> getter steps are to
247239
248240    1. [=close a subscription|Close=]  [=this=] .
249241
250-     1. [=AbortController/Signal abort=]  [=this=] 's [=Subscriber/complete or error controller=] .
251- 
252242    1. Run [=this=] 's [=Subscriber/complete algorithm=] .
253243
254244       [=Assert=] : No <a spec=webidl lt="an exception was thrown">exception was thrown</a> .
@@ -274,43 +264,51 @@ The <dfn attribute for=Subscriber><code>signal</code></dfn> getter steps are to
274264<div algorithm> 
275265  To <dfn>close a subscription</dfn>  given a {{Subscriber}}  |subscriber|, run these steps:
276266
277-     1. Set  |subscriber|'s [=Subscriber/active=]  boolean to  false.
267+     1. If  |subscriber|'s [=Subscriber/active=]  is  false, then return .
278268
279-   <div class=note> 
280-     <p> This algorithm intentionally does not have script-running side-effects; it just updates the
281-     internal state of a {{Subscriber}} . It's important that this algorithm sets
282-     [=Subscriber/active=]  to false and clears all of the callback algorithms *before* running any
283-     script, because running script <span class=allow-2119> may</span>  reentrantly invoke one of the
284-     methods that closed the subscription in the first place. And closing the subscription <span 
285-     class=allow-2119> must</span>  ensure that even if a method gets reentrantly invoked, none of the
286-     {{SubscriptionObserver}}  callbacks are ever invoked again. Consider this example:</p> 
287- 
288-     <div class=example id=reentrant-example> 
289-       <pre highlight=js> 
290- let innerSubscriber = null;
291- const producedValues = [];
292- 
293- const controller = new AbortController();
269+        <div class=note> 
270+          <p> This guards against re-entrant invocation, which can happen in the "producer-initiated"
271+          unsubscription case. Consider the following example:</p> 
272+          <div class=example id=re-entrant-close> 
273+            <pre highlight=js> 
274+ const outerController = new AbortController();
294275const observable = new Observable(subscriber => {
295-   innerSubscriber = subscriber;
276+   subscriber.addTeardown(() => {
277+     // 2.) This teardown executes inside the "Close" algorithm, while it's
278+     //     running. Aborting the downstream signal run its abort algorithms,
279+     //     one of which is the currently-running "Close" algorithm.
280+     outerController.abort();
281+   });
282+ 
283+   // 1.) This immediately invokes the "Close" algorithm, which
284+   //     sets subscriber.active to false.
296285  subscriber.complete();
297286});
298287
299- observable.subscribe({
300-   next: v => producedValues.push(v),
301-   complete: () => innerSubscriber.next('from complete' ),
302- 
303-   }, {signal: controller.signal}
304- );
305- 
306- // This invokes the complete() callback, and even though it invokes next() from
307- // within, the given next() callback will never run, because the subscription
308- // has already been "closed" before the complete() callback actually executes.
309- controller.abort();
310- console.assert(producedValues.length === 0);
311-       </pre> 
312-     </div> 
313-   </div> 
288+ observable.subscribe({}, {signal: outerController.signal});
289+            </pre> 
290+          </div> 
291+        </div> 
292+ 
293+     1. Set |subscriber|'s [=Subscriber/active=]  boolean to false.
294+ 
295+     1. [=AbortSignal/Signal abort=]  |subscriber|'s [=Subscriber/subscription controller=] .
296+ 
297+        Issue: Abort with an appropriate abort reason.
298+ 
299+     1. [=list/For each=]  |teardown| of |subscriber|'s [=Subscriber/teardown callbacks=]  sorted in
300+        reverse insertion order:
301+ 
302+        1. If |subscriber|'s [=relevant global object=]  is a {{Window}}  object, and its [=associated 
303+           Document=]  is not [=Document/fully active=] , then abort these steps.
304+ 
305+           Note: This step runs repeatedly because each |teardown| could result in the above
306+           {{Document}}  becoming inactive.
307+ 
308+        1. [=Invoke=]  |teardown|.
309+ 
310+           If <a spec=webidl lt="an exception was thrown">an exception |E| was thrown</a> , call
311+           |subscriber|'s {{Subscriber/error()}}  method with |E|.
314312</div> 
315313
316314<h3 id=observable-api>The {{Observable}} interface</h3> 
@@ -526,37 +524,16 @@ An <dfn>internal observer</dfn> is a [=struct=] with the following [=struct/item
526524      : [=Subscriber/complete algorithm=] 
527525      :: |internal observer|'s [=internal observer/complete steps=] 
528526
529-       : [=Subscriber/signal=] 
530-       :: The result of [=creating a dependent abort signal=]  from the list «|subscriber|'s
531-          [=Subscriber/complete or error controller=] 's [=AbortController/signal=], |options|' s
532-          {{SubscribeOptions/signal}}  if it is non-null», using {{AbortSignal}} , and the [=current 
533-          realm=] .
534- 
535-     1. If |subscriber|'s [=Subscriber/signal=]  is [=AbortSignal/aborted=] , then [=close a 
536-        subscription|close=]  |subscriber|.
527+     1. If |options|'s {{SubscribeOptions/signal}}  [=map/exists=] , then:
537528
538-        Note: This can happen when  {{SubscribeOptions}} 's {{SubscribeOptions/signal}}  is already 
539-        [=AbortSignal/aborted=] .
529+        1. If |options| 's {{SubscribeOptions/signal}}  is [=AbortSignal/aborted=] , then  [=close a 
530+           subscription|close=]   |subscriber| .
540531
541-     1. Otherwise, [=AbortSignal/add|add the following abort algorithm=]  to |subscriber |'s
542-        [=Subscriber /signal=]  :
532+     1. Otherwise, [=AbortSignal/add|add the following abort algorithm=]  to |options |'s
533+        {{SubscribeOptions /signal}}  :
543534
544535       1. [=close a subscription|Close=]  |subscriber|.
545536
546-        1. [=list/For each=]  |teardown| of |subscriber|'s [=Subscriber/teardown callbacks=]  sorted in
547-           reverse insertion order:
548- 
549-           1. If |subscriber|'s [=relevant global object=]  is a {{Window}}  object, and its
550-              [=associated Document=]  is not [=Document/fully active=] , then abort these steps.
551- 
552-              Note: This step runs repeatedly because each |teardown| could result in the above
553-              {{Document}}  becoming inactive.
554- 
555-           1. [=Invoke=]  |teardown|.
556- 
557-              If <a spec=webidl lt="an exception was thrown">an exception |E| was thrown</a> , call
558-              |subscriber|'s {{Subscriber/error()}}  method with |E|.
559- 
560537    1. If [=this=] 's [=Observable/subscribe callback=]  is a {{SubscribeCallback}} , [=invoke=]  it
561538       with |subscriber|.
562539
@@ -618,9 +595,9 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w
618595
619596             Note: This will "unsubscribe" from |sourceObservable|, if it has been subscribed to by
620597             this point. This is because |sourceObservable| is subscribed to with the "outer"
621-              |subscriber|'s [=Subscriber/signal=]   as an input  signal, and that signal will get 
622-              [=AbortSignal/signal abort|aborted=]  when the "outer" |subscriber|'s 
623-              {{Subscriber/complete()}}  is called above (and below).
598+              |subscriber|'s [=Subscriber/subscription controller=]'  s  [=AbortController/ signal=]  as 
599+              an input signal, and that signal will get  [=AbortSignal/signal abort|aborted=]  when the
600+              "outer" |subscriber|'s  {{Subscriber/complete()}}  is called above (and below).
624601
625602          : [=internal observer/error steps=] 
626603          :: Run |subscriber|'s {{Subscriber/complete()}}  method.
@@ -631,7 +608,7 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w
631608          mirror |sourceObservable| uninterrupted.
632609
633610       1. Let |options| be a new {{SubscribeOptions}}  whose {{SubscribeOptions/signal}}  is
634-           |subscriber|'s [=Subscriber/signal=] .
611+           |subscriber|'s [=Subscriber/subscription controller=]'  s  [=AbortController/ signal=] .
635612
636613       1. <a for=Observable lt="subscribe to an Observable">Subscribe</a>  to |notifier| given
637614          |notifierObserver| and |options|.
@@ -705,7 +682,7 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w
705682          :: Run |subscriber|'s {{Subscriber/complete()}}  method.
706683
707684       1. Let |options| be a new {{SubscribeOptions}}  whose {{SubscribeOptions/signal}}  is
708-           |subscriber|'s [=Subscriber/signal=] .
685+           |subscriber|'s [=Subscriber/subscription controller=]'  s  [=AbortController/ signal=] .
709686
710687       1. <a for=Observable lt="subscribe to an Observable">Subscribe</a>  to |sourceObservable|
711688          given |sourceObserver| and |options|.
@@ -751,7 +728,7 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w
751728          :: Run |subscriber|'s {{Subscriber/complete()}}  method.
752729
753730       1. Let |options| be a new {{SubscribeOptions}}  whose {{SubscribeOptions/signal}}  is
754-           |subscriber|'s [=Subscriber/signal=] .
731+           |subscriber|'s [=Subscriber/subscription controller=]'  s  [=AbortController/ signal=] .
755732
756733       1. <a for=Observable lt="subscribe to an Observable">Subscribe</a>  to |sourceObservable|
757734          given |sourceObserver| and |options|.
@@ -793,7 +770,7 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w
793770          :: Run |subscriber|'s {{Subscriber/complete()}}  method.
794771
795772       1. Let |options| be a new {{SubscribeOptions}}  whose {{SubscribeOptions/signal}}  is
796-           |subscriber|'s [=Subscriber/signal=] .
773+           |subscriber|'s [=Subscriber/subscription controller=]'  s  [=AbortController/ signal=] .
797774
798775       1. <a for=Observable lt="subscribe to an Observable">Subscribe</a>  to |sourceObservable|
799776          given |sourceObserver| and |options|.
@@ -832,7 +809,7 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w
832809          :: Run |subscriber|'s {{Subscriber/complete()}}  method.
833810
834811       1. Let |options| be a new {{SubscribeOptions}}  whose {{SubscribeOptions/signal}}  is
835-           |subscriber|'s [=Subscriber/signal=] .
812+           |subscriber|'s [=Subscriber/subscription controller=]'  s  [=AbortController/ signal=] .
836813
837814       1. <a for=Observable lt="subscribe to an Observable">Subscribe</a>  to |sourceObservable|
838815          given |sourceObserver| and |options|.
@@ -911,7 +888,7 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w
911888                |subscriber|'s {{Subscriber/complete()}}  method.
912889
913890       1. Let |options| be a new {{SubscribeOptions}}  whose {{SubscribeOptions/signal}}  is
914-           |subscriber|'s [=Subscriber/signal=] .
891+           |subscriber|'s [=Subscriber/subscription controller=]'  s  [=AbortController/ signal=] .
915892
916893       1. <a for=Observable lt="subscribe to an Observable">Subscribe</a>  to |sourceObservable|
917894          given |sourceObserver| and |options|.
@@ -976,7 +953,7 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w
976953                 had not yet completed. Until right now!
977954
978955     1. Let |innerOptions| be a new {{SubscribeOptions}}  whose {{SubscribeOptions/signal}}  is
979-         |subscriber|'s [=Subscriber/signal=] .
956+         |subscriber|'s [=Subscriber/subscription controller=]'  s  [=AbortController/ signal=] .
980957
981958     1. <a for=Observable lt="subscribe to an Observable">Subscribe</a>  to |innerObservable| given
982959        |innerObserver| and |innerOptions|.
@@ -1044,7 +1021,7 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w
10441021                {{Subscriber/complete()}}  method.
10451022
10461023       1. Let |options| be a new {{SubscribeOptions}}  whose {{SubscribeOptions/signal}}  is
1047-           |subscriber|'s [=Subscriber/signal=] .
1024+           |subscriber|'s [=Subscriber/subscription controller=]'  s  [=AbortController/ signal=] .
10481025
10491026       1. <a for=Observable lt="subscribe to an Observable">Subscribe</a>  to |sourceObservable|
10501027          given |sourceObserver| and |options|.
@@ -1098,7 +1075,8 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w
10981075     1. Let |innerOptions| be a new {{SubscribeOptions}}  whose {{SubscribeOptions/signal}}  is the
10991076        result of [=creating a dependent abort signal=]  from the list
11001077        «|activeInnerAbortController|'s [=AbortController/signal=], |subscriber|' s
1101-         [=Subscriber/signal=] », using {{AbortSignal}} , and the [=current realm=] .
1078+         [=Subscriber/subscription controller=] 's [=AbortController/signal=] », using
1079+         {{AbortSignal}} , and the [=current realm=] .
11021080
11031081     1. <a for=Observable lt="subscribe to an Observable">Subscribe</a>  to |innerObservable| given
11041082        |innerObserver| and |innerOptions|.
@@ -1134,10 +1112,9 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w
11341112             reason=] .
11351113
11361114          Note: All we have to do here is [=reject=]  |p|. Note that the subscription to [=this=] 
1137-           {{Observable}}  will also be canceled automatically, since the "inner"
1138-           [=Subscriber/signal=]  (created during <a for=Observable lt="subscribe to an 
1139-           Observable">subscription</a> ) is a [=AbortSignal/dependent signal=]  of |options|'s
1140-           {{SubscribeOptions/signal}} .
1115+           {{Observable}}  will also be closed automatically, since the "inner" Subscriber gets
1116+           [=close a subscription|closed=]  in response to |options|'s {{SubscribeOptions/signal}} 
1117+           getting [=AbortSignal/signal abort=] .
11411118
11421119    1. Let |values| be a new [=list=] .
11431120
@@ -1537,8 +1514,8 @@ partial interface EventTarget {
15371514               Note: This is meant to capture the fact that |event target| can be garbage collected
15381515               by the time this algorithm runs upon subscription.
15391516
1540-             1. If |subscriber|'s [=Subscriber/signal=]   is  [=AbortSignal/aborted=] , abort these 
1541-                steps.
1517+             1. If |subscriber|'s [=Subscriber/subscription controller=]'  s  [=AbortController/signal=] 
1518+                is  [=AbortSignal/aborted=] , abort these  steps.
15421519
15431520            1. [=Add an event listener=]  with |event target| and an [=event listener=]  defined as follows:
15441521
0 commit comments