When teeing a stream, if one branch is cancelled while the other branch is read until the end, then the cancel promise of the first branch never resolves.
Reproduction case
const readable = new ReadableStream({
start(controller) {
for (let chunk of ["a", "b", "c"]) {
controller.enqueue(chunk);
}
controller.close();
}
});
const [leftStream, rightStream] = readable.tee();
(async () => {
const reader = leftStream.getReader();
// Cancel the left branch immediately.
console.log("left cancel start");
let cancelPromise = reader.cancel();
// The left branch never finishes cancelling.
let cancelResult = await cancelPromise;
console.log("left cancel done", cancelResult); // never reached
})();
(async () => {
const reader = rightStream.getReader();
// Read all chunks from the right branch.
while (true) {
const {value, done} = await reader.read();
console.log("right read:", {value, done});
if (done) break;
}
// The right branch has read all the chunks.
let closedResult = await reader.closed;
console.log("right closed", closedResult);
})();
Expected results
The left branch should finish cancelling once all chunks have been read from the original stream (as a result of the right branch pulling them).
Actual results
The left branch never finishes cancelling.
Investigation
Currently, the specification for ReadableStreamTee only resolves cancelPromise when both branches are cancelled. However, I believe this needs to happen when either both branches are cancelled, or when the last chunk has been pulled (i.e. during the "If done is true" step of pullAlgorithm).
When teeing a stream, if one branch is cancelled while the other branch is read until the end, then the cancel promise of the first branch never resolves.
Reproduction case
Expected results
The left branch should finish cancelling once all chunks have been read from the original stream (as a result of the right branch pulling them).
Actual results
The left branch never finishes cancelling.
Investigation
Currently, the specification for ReadableStreamTee only resolves cancelPromise when both branches are cancelled. However, I believe this needs to happen when either both branches are cancelled, or when the last chunk has been pulled (i.e. during the "If done is true" step of pullAlgorithm).