I'm trying to read a file with minimal amount of data copy using a ReadableStreamBYOBReader
, but it seems that reader isn't reading at and writing to the correct offsets in Chrome.
In the following example, I'm simply calling ReadableStreamBYOBReader.read
twice to see what is happening to the buffers.
The example is derived from the one on developer.mozilla.org (copying their example as is also produces the same behavior in the debugger)
<input type="file" onchange="upload(event)" />
<script>
async function upload(event) {
const reader = event.target.files[0].stream().getReader({ mode: 'byob' });
let buffer = new ArrayBuffer(16777216);
let offset = 0;
const read1 = await reader.read(new Uint8Array(buffer, offset, 8388608));
console.log('1', read1.value, new Uint8Array(read1.value.buffer));
buffer = read1.value.buffer;
offset += read1.value.byteLength;
const read2 = await reader.read(new Uint8Array(buffer, offset, 8388608));
console.log('2', read2.value, new Uint8Array(read2.value.buffer));
}
</script>
I'm expecting readX.value
to be the ArrayBufferView
corresponding to what has just been read by reader.read
. (the ArrayBufferView
being an offset view of the 16MB buffer allocated at the beginning)
I'm expecting new Uint8Array(readX.value.buffer)
to be the full buffer in both cases, filled with only one reader.read
's worth of data in the first console.log
, and two reader.read
's worth of data in the second.
That's exactly what I am observing in Firefox :
1 Uint8Array(65536) [ 0, 0, 0, 32, 102, … ] Uint8Array(16777216) [ 0, 0, 0, 32, 102, … ]
2 Uint8Array(65536) [ 100, 63, 56, 65, 149, … ] Uint8Array(16777216) [ 0, 0, 0, 32, 102, … ]
But not in Chrome :
1 Uint8Array(65536) [ 0, 0, 0, 32, 102, …] Uint8Array(16777216) [ 0, 0, 0, 32, 102, …]
2 Uint8Array(524288) [ 28, 196, 91, 173, 156, …] Uint8Array(16777216) [ 100, 63, 56, 65, 149, …]
In the file I used for the test:
[ 0, 0, 0, 32, 102]
is the beginning of the file[100, 63, 56, 65, 149]
is offset 65536[ 28, 192, 91, 173, 156]
is offset 131072As expected, with Firefox, the two readX.value
are the chunks that were just read, one next to the other ; and the new Uint8Array
one is the full buffer, showing both chunks next to each other.
But with Chrome, in the second call, the read2.value
somehow contains the content of offset 131072 (while it only read a chunk of 64k before) ; and it seems it wrote the expected content (starting from offset 65536) at the beginning of the buffer, ignoring the offset given as parameter in the second read
call.
Note for re-testing: Chrome is annoying as it never reads chunks the same size, and sometimes read a few MB at once, thus the big 8MB buffer for reading (this behavior is not reproduced when reading to a small (few kB) ArrayBufferView)
To report a Chrome bug, use crbug.com/new (and/or search for existing issues on crbug.com).
This particular issue sounds like crbug.com/1492093, which has been fixed two weeks ago.