Re: [whatwg/dom] Define a 'PromiseController' and 'PromiseSignal' interface. (#434)

domenic commented on this pull request.

Big-ticket items:

- This isn't specific to promises, so the names are probably not right
- Is this about cancelation or abortion?
- It's unclear how the abort steps would be used by other specs

> @@ -1419,6 +1419,103 @@ that gave folks all the wrong ideas. <a>Events</a> do not represent or cause act
 can only be used to influence an ongoing one.
 
 
+<h3 id=controlling-promises>Controlling {{Promise}}s</h3>

This probably doesn't belong under the "Events" section. I'm not sure if it belongs in DOM at all, but I don't know of a better place really, so who knows... new WHATWG spec time?

> @@ -1419,6 +1419,103 @@ that gave folks all the wrong ideas. <a>Events</a> do not represent or cause act
 can only be used to influence an ongoing one.
 
 
+<h3 id=controlling-promises>Controlling {{Promise}}s</h3>
+
+Though {{Promise}} objects don't have any built-in cancellation mechanism, many {{Promise}}-vending

I prefer "cancelation" with one "l" but as long as we're consistent we'll be good.

> @@ -1419,6 +1419,103 @@ that gave folks all the wrong ideas. <a>Events</a> do not represent or cause act
 can only be used to influence an ongoing one.
 
 
+<h3 id=controlling-promises>Controlling {{Promise}}s</h3>
+
+Though {{Promise}} objects don't have any built-in cancellation mechanism, many {{Promise}}-vending
+APIs require cancellation semantics. {{PromiseController}} is meant to support these requirements by
+providing an {{PromiseController/abort()}} method that toggles the state of a corresponding
+{{PromiseSignal}} object. The API which wishes to support cancellation can accept such a
+{{PromiseSignal}}, and use its state to determine how (not) to proceed.
+
+Upon {{PromiseController/abort()}}, the relevant {{Promise}} will reject with an
+<dfn exception>AbortError</dfn> [=simple exception=].
+
+<div class=note>
+ For example, a hypothetical <code>DoAmazingness({ ... })</code> method could accept a

Don't capitalize doAmazingness

> @@ -1419,6 +1419,103 @@ that gave folks all the wrong ideas. <a>Events</a> do not represent or cause act
 can only be used to influence an ongoing one.
 
 
+<h3 id=controlling-promises>Controlling {{Promise}}s</h3>
+
+Though {{Promise}} objects don't have any built-in cancellation mechanism, many {{Promise}}-vending
+APIs require cancellation semantics. {{PromiseController}} is meant to support these requirements by
+providing an {{PromiseController/abort()}} method that toggles the state of a corresponding
+{{PromiseSignal}} object. The API which wishes to support cancellation can accept such a
+{{PromiseSignal}}, and use its state to determine how (not) to proceed.
+
+Upon {{PromiseController/abort()}}, the relevant {{Promise}} will reject with an

This isn't always the case, right? It depends on what the accepting method will do. I think this needs to be phrased as a convention or something, since it's not enforced.

> @@ -1419,6 +1419,103 @@ that gave folks all the wrong ideas. <a>Events</a> do not represent or cause act
 can only be used to influence an ongoing one.
 
 
+<h3 id=controlling-promises>Controlling {{Promise}}s</h3>
+
+Though {{Promise}} objects don't have any built-in cancellation mechanism, many {{Promise}}-vending

Is it cancel(l)ation or abortion? The API says abortion...

> + {{PromiseSignal}} according to their needs.
+</div>
+
+<h4 id=interface-promisecontroller>Interface {{PromiseController}}</h3>
+
+<pre class="idl">
+[Constructor(), Exposed=(Window,Worker)]
+interface PromiseController {
+  readonly attribute PromiseSignal signal;
+
+  void abort();
+};
+</pre>
+<dl class=domintro>
+ <dt><code><var>controller</var> = new <a constructor lt="PromiseController()">PromiseController</a>()</code>
+ <dd>Returns a new <var>controller</var> whose {{PromiseController/signal}} attribute value is set

I'd remove "attribute value" (in general mentioning "attributes" in dev-facing docs is just confusing).

> +};
+</pre>
+<dl class=domintro>
+ <dt><code><var>controller</var> = new <a constructor lt="PromiseController()">PromiseController</a>()</code>
+ <dd>Returns a new <var>controller</var> whose {{PromiseController/signal}} attribute value is set
+ to a newly created {{PromiseSignal}} object.
+
+ <dt><code><var>controller</var> . </code>{{PromiseController/signal}}
+ <dd>Returns the {{PromiseSignal}} object associated with this object.
+
+ <dt><code><var>controller</var> . </code>{{PromiseController/abort()}}
+ <dd>Invoking this method will set this object's {{PromiseSignal}}'s [=PromiseSignal/aborted flag=],
+ thereby signaling to any observers that the associated activity should be aborted.
+</dl>
+
+The <dfn attribute for=PromiseController>signal</dfn> attribute must return the value to which it

Needs `<code>`

> + <dd>Returns a new <var>controller</var> whose {{PromiseController/signal}} attribute value is set
+ to a newly created {{PromiseSignal}} object.
+
+ <dt><code><var>controller</var> . </code>{{PromiseController/signal}}
+ <dd>Returns the {{PromiseSignal}} object associated with this object.
+
+ <dt><code><var>controller</var> . </code>{{PromiseController/abort()}}
+ <dd>Invoking this method will set this object's {{PromiseSignal}}'s [=PromiseSignal/aborted flag=],
+ thereby signaling to any observers that the associated activity should be aborted.
+</dl>
+
+The <dfn attribute for=PromiseController>signal</dfn> attribute must return the value to which it
+was initialized. When a {{PromiseController}} is created, the attribute must be initialized to a
+newly created {{PromiseSignal}} object.
+
+The <dfn method for=PromiseController><code>abort()</code></dfn>, when invoked, must run these

Missing "method"

> + <dd>Returns true if this {{PromiseSignal}} has been aborted, and false otherwise.
+</dl>
+
+Each {{PromiseSignal}} has an <dfn for=PromiseSignal>aborted flag</dfn> which is unset unless
+otherwise specified.
+
+Each {{PromiseSignal}} has an <dfn for=PromiseSignal>abort steps</dfn> algorithm which is
+executed when its [=PromiseSignal/aborted flag=] is set. Unless otherwise specified, this
+algorithm is a no-op.
+
+<p class="note no-backref">The [=PromiseSignal/abort steps=] algorithm enables APIs with more
+complex requirements to react in a reasonable way to {{PromiseController/abort()}}. For example,
+a given API's [=PromiseSignal/aborted flag=] may need to be propagated to a cross-thread
+environment (like a Service Worker).
+
+The <dfn attribute for=PromiseSignal>aborted</dfn> attribute's getter must return true if the

Needs `<code>`

> +  readonly attribute boolean aborted;
+
+  attribute EventHandler onabort;
+};
+</pre>
+<dl class=domintro>
+ <dt><code><var>signal</var> . </code>{{PromiseSignal/aborted}}
+ <dd>Returns true if this {{PromiseSignal}} has been aborted, and false otherwise.
+</dl>
+
+Each {{PromiseSignal}} has an <dfn for=PromiseSignal>aborted flag</dfn> which is unset unless
+otherwise specified.
+
+Each {{PromiseSignal}} has an <dfn for=PromiseSignal>abort steps</dfn> algorithm which is
+executed when its [=PromiseSignal/aborted flag=] is set. Unless otherwise specified, this
+algorithm is a no-op.

Hmm, so how would this be used? It may need an example. Is the idea that e.g. fetch() would accept a `signal`, then _mutate_ its abort steps to abort the fetch? What if you pass the same signal in to multiple fetches? Maybe it should be a list of abort steps, so that consumers append to the list?

> @@ -1419,6 +1419,103 @@ that gave folks all the wrong ideas. <a>Events</a> do not represent or cause act
 can only be used to influence an ongoing one.
 
 
+<h3 id=controlling-promises>Controlling {{Promise}}s</h3>
+
+Though {{Promise}} objects don't have any built-in cancellation mechanism, many {{Promise}}-vending
+APIs require cancellation semantics. {{PromiseController}} is meant to support these requirements by
+providing an {{PromiseController/abort()}} method that toggles the state of a corresponding
+{{PromiseSignal}} object. The API which wishes to support cancellation can accept such a
+{{PromiseSignal}}, and use its state to determine how (not) to proceed.
+
+Upon {{PromiseController/abort()}}, the relevant {{Promise}} will reject with an
+<dfn exception>AbortError</dfn> [=simple exception=].

You can't just define new simple exceptions, but I know you are aware, per your comments about hand-waving. Still, something to take care of before this gets merged.

> @@ -1419,6 +1419,103 @@ that gave folks all the wrong ideas. <a>Events</a> do not represent or cause act
 can only be used to influence an ongoing one.
 
 
+<h3 id=controlling-promises>Controlling {{Promise}}s</h3>

This actually isn't really specific to promises. For example it could be used to cancel a stream:

```js
const readableStream = getStream({ signal });

// ... later ...
signal.abort(); // basically the same as readableStream.cancel()
```

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/dom/pull/434#pullrequestreview-31296486

Received on Thursday, 6 April 2017 12:50:59 UTC