-
Notifications
You must be signed in to change notification settings - Fork 164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Do the abort steps of ReadableStreamPipeTo really guarantee the abort callback to be called before cancel? #1229
Comments
This seems extremely related to #1208 and similar things @MattiasBuelens was working on... but the fact that the reference implementation passes all WPTs implies the current spec should be good enough. Does streams/reference-implementation/lib/abstract-ops/readable-streams.js Lines 150 to 177 in e9355ce
Promise.all([dest.abort(), source.cancel()]) so I am not sure where you are getting that...
|
This happens because the writable stream is not yet started. If you add a delay before you call abort and cancel, you get the events in the expected order: promise_test(async t => {
const events = [];
const rs = new ReadableStream({
pull(controller) {
controller.error('failed to abort');
},
cancel() {
events.push('cancel');
return Promise.reject(error1);
}
}, { highWaterMark: 0 });
const ws = new WritableStream({
abort() {
events.push('abort');
return Promise.reject(error2);
}
});
await flushAsyncEvents(); // <<< the important bit
await promise_rejects_exactly(t, error2, Promise.all([ws.abort(), rs.cancel()]), 'The abort rejection happens first in this case');
assert_array_equals(events, ['abort', 'cancel'], 'abort() is called first in this case');
}, '#1229'); I agree that this is surprising: we don't wait for the readable stream to be started before we call its let abortController = new AbortController();
const rs = new ReadableStream({
async start(controller) {
while (!abortController.signal.aborted) {
controller.enqueue("a");
await new Promise(r => setTimeout(r, 1000));
}
},
cancel(reason) {
controller.abort(reason);
}
}); See also #1208 (comment). |
Oh wait, hang on. That doesn't actually explain why It looks like the problem is that, even when the pipe is immediately aborted (with an aborted streams/reference-implementation/lib/abstract-ops/readable-streams.js Lines 293 to 294 in e9355ce
The implementation of I've tried fixing this for the case where the pipe didn't start any writes at all (#1208 (comment)), but that caused even more problems... 😛 |
Thanks, #1208 looks indeed very much related! The current Gecko implementation does not wait at all there and thus calls the shutdown actions synchronously, while both the reference impl and Blink wait there per the following code: var rs = new ReadableStream({ cancel() { console.log("canceled") } });
var ws = new WritableStream({ abort() { console.log("aborted") } });
var abortController = new AbortController();
var signal = abortController.signal;
abortController.abort();
rs.pipeTo(ws, { signal });
console.log("foo")
// Reference: foo aborted canceled
// Blink: foo aborted canceled
// Gecko: canceled foo aborted Will #1208 change the behavior here as Gecko does? |
In its current state, no. Personally, I think we should make |
Step 14 of the https://streams.spec.whatwg.org/#readable-stream-pipe-to is basically
Promise.all([dest.abort(), source.cancel()])
, assuming the states are writable/readable respectively. One WPT test for this asserts thatabort()
is called beforecancel()
: https://github.com/web-platform-tests/wpt/blob/285addceabb4443562a9b93d789b17230c3d6e20/streams/piping/abort.any.js#L215-L237Blink passes this test, but not sure how. A slightly modified test without AbortSignal shows that the abort callback is called after the cancel callback (because the latter is called synchronously while the former is not), so I'd expect same for the AbortSignal test:
Am I understanding something wrong?
The text was updated successfully, but these errors were encountered: