[whatwg/streams] Close should be idempotent (#1136)

Currently, the spec requires some "close" operations to be non-idempotent:

> The `close()` method steps are:
>   If `! ReadableStreamDefaultControllerCanCloseOrEnqueue(this)` is false, throw a TypeError exception.
>   Perform `! ReadableStreamDefaultControllerClose(this)`.

The following code causes an exception in both Chrome and Deno:

```js
let ctrl
new ReadableStream({start(val) {ctrl = val}})

ctrl.close()
ctrl.close()
// error: Uncaught TypeError: The stream controller cannot close or enqueue.
```

Making "close" operations non-idempotent is a questionable choice (severity = minor). I'm under the impression that in modern high-level languages, there's a general trend of making all close operations idempotent. When dealing with callback-infested APIs, it's common to have multiple code paths / callbacks leading to the same cleanup call. Code will assume that it's okay to `.close()` many times, erring on the side of "closing for sure" rather than leaking.

When using Deno (which appears to implement streams faithfully to spec), this was causing minor practical issues for me; sometimes a stream would be closed by the underlying runtime due to client disconnect, and sometimes it wouldn't; my code was _always_ calling `.close()`, which sometimes resulted in unhandled exceptions.

Of course there's an easy workaround of `try/catch`, but it shouldn't be necessary here.

The same logic applies to `.cancel()` and other forms of deinit/abort/cleanup, but I haven't checked if those have the same issues.

-- 
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/streams/issues/1136

Received on Saturday, 5 June 2021 16:07:32 UTC