diff --git a/spec.bs b/spec.bs index 69c5ad9..b25552d 100644 --- a/spec.bs +++ b/spec.bs @@ -345,7 +345,7 @@ dictionary SubscribeOptions { }; callback Predicate = boolean (any value, unsigned long long index); -callback Reducer = any (any accumulator, any currentValue); +callback Reducer = any (any accumulator, any currentValue, unsigned long long index); callback Mapper = any (any value, unsigned long long index); // Differs from Mapper only in return type, since this callback is exclusively // used to visit each element in a sequence, not transform it. @@ -1604,7 +1604,67 @@ For now, see [https://github.com/wicg/observable#operators](https://github.com/w The reduce(|reducer|, |initialValue|, |options|) method steps are: - 1. TODO: Spec this and use |reducer|, |initialValue|, and |options|. + 1. Let |p| [=a new promise=]. + + 1. Let |controller| be a [=new=] {{AbortController}}. + + 1. Let |internal options| be a new {{SubscribeOptions}} whose {{SubscribeOptions/signal}} is the + result of [=creating a dependent abort signal=] from the list + «|controller|'s [=AbortController/signal=], |options|'s + {{SubscribeOptions/signal}} if non-null», using {{AbortSignal}}, and the [=current realm=]. + + 1. If |internal options|'s {{SubscribeOptions/signal}} is [=AbortSignal/aborted=], then: + + 1. [=Reject=] |p| with |internal options|'s {{SubscribeOptions/signal}}'s + [=AbortSignal/abort reason=]. + + 1. Return |p|. + + 1. [=AbortSignal/add|Add the following abort algorithm=] to |internal options|'s + {{SubscribeOptions/signal}}: + + 1. [=Reject=] |p| with |internal options|'s {{SubscribeOptions/signal}}'s [=AbortSignal/abort + reason=]. + + 1. Let |idx| be an {{unsigned long long}}, initially 0. + + 1. Let |accumulator| be |initialValue| if it is given, and uninitialized otherwise. + + 1. Let |observer| be a new [=internal observer=], initialized as follows: + + : [=internal observer/next steps=] + :: + 1. If |accumulator| is uninitialized (meaning no |initialValue| was passed in), then set + |accumulator| to the passed in |value|, set |idx| to |idx| + 1, and abort these steps. + + Note: This means that |reducer| will not be called with the first |value| that [=this=] + produces set as the {{Reducer/currentValue}}. Rather, when the *second* value is + eventually emitted, we will call |reducer| with *it* as the {{Reducer/currentValue}}, + and the first value (that we're saving here) as the {{Reducer/accumulator}}. + + 1. [=Invoke=] |reducer| with |accumulator| as {{Reducer/accumulator}}, the passed in + |value| as {{Reducer/currentValue}}, and |idx| as {{Reducer/index}}. Let |result| be + the returned value. + + If an exception |E| was thrown, then + [=reject=] |p| with |E|, and [=AbortController/signal abort=] |controller| with |E|. + + 1. Set |idx| to |idx| + 1. + + 1. Set |accumulator| to |result|. + + : [=internal observer/error steps=] + :: [=Reject=] |p| with the passed in error. + + : [=internal observer/complete steps=] + :: 1. If |accumulator| is not "unset", then [=resolve=] |p| with |accumulator|. + + Otherwise, [=reject=] |p| with a {{TypeError}}. + + 1. Subscribe to [=this=] given |observer| + and |internal options|. + + 1. Return |p|.