Skip to content

Instantly share code, notes, and snippets.

@domenic

domenic/v1.js Secret

Forked from jakearchibald/gist:69a8feb459d799e89008
Last active August 29, 2015 14:14
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save domenic/440db8eac99c5b41bf95 to your computer and use it in GitHub Desktop.
Save domenic/440db8eac99c5b41bf95 to your computer and use it in GitHub Desktop.
async fetchWithProgress(url, progress) {
let body = '';
const response = await fetch(url);
const length = Number(response.headers.get('Content-Length'));
const decoder = new TextDecoder();
await readWithProgress();
return body;
async function readWithProgress() {
while (response.body.state === 'readable') {
body += decoder.decode(response.body.read(), { stream: true });
}
if (length) {
progress(body.length / length);
}
if (response.body.state === 'waiting') {
await response.body.ready;
return readWithProgress();
}
}
}
// usage
const progressEl = document.querySelector('.progress');
progressEl.max = 1;
fetchWithProgress('/blah.json', function(val) {
progressEl.value = val;
}).then(JSON.parse).then(doStuff);
// Based on https://github.com/whatwg/streams/blob/master/Examples.md#getting-the-next-piece-of-available-data
const EOF = Symbol("ReadableStream getNext EOF");
async function getNext(stream) {
await stream.ready;
if (stream.state === "closed") {
return EOF;
}
// If stream is "errored", this will throw, causing the promise to be rejected.
return stream.read();
}
async fetchWithProgress(url, progress) {
let body = '';
const response = await fetch(url);
const length = Number(response.headers.get('Content-Length'));
const decoder = new TextDecoder();
while ((const chunk = await getNext(response.body)) !== EOF) {
body += decoder.decode(chunk, { stream: true });
if (length) {
progress(body.length / length);
}
}
return body;
}
// usage
const progressEl = document.querySelector('.progress');
progressEl.max = 1;
fetchWithProgress('/blah.json', function(val) {
progressEl.value = val;
}).then(JSON.parse).then(doStuff);
@domenic
Copy link
Author

domenic commented Jan 27, 2015

v2.js fires events more often than v1.js (and is a bit less efficient, since if multiple chunks are available at once it will still delay a microtask in between each of them).

Also I think all of these make the mistake of assuming the stream chunks are strings, whereas they're actually ArrayBuffers.Fixed with recent edits

@domenic
Copy link
Author

domenic commented Feb 3, 2015

Both are not very efficient compared to using ReadableByteStream's readInto method (which would allow you to pre-allocated an ArrayBuffer up front and read data into it, instead of having the UA allocate new ones for each chunk). I'm unclear whether that'll be shipping in M43 though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment