forked from davidflanagan/jstdg7
-
Notifications
You must be signed in to change notification settings - Fork 0
/
streamBody.js
54 lines (50 loc) · 2.65 KB
/
streamBody.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* An asynchronous function for streaming the body of a Response object
* obtained from a fetch() request. Pass the Response object as the first
* argument followed by two optional callbacks.
*
* If you specify a function as the second argument, that reportProgress
* callback will be called once for each chunk that is received. The first
* argument passed is the total number of bytes received so far. The second
* argument is a number between 0 and 1 specifying how complete the download
* is. If the Response object has no "Content-Length" header, however, then
* this second argument will always be NaN.
*
* If you want to process the data in chunks as they arrive, specify a
* function as the third argument. The chunks will be passed, as Uint8Array
* objects, to this processChunk callback.
*
* streamBody() returns a Promise that resolves to a string. If a processChunk
* callback was supplied then this string is the concatenation of the values
* returned by that callback. Otherwise the string is the concatenation of
* the chunk values converted to UTF-8 strings.
*/
async function streamBody(response, reportProgress, processChunk) {
// How many bytes are we expecting, or NaN if no header
let expectedBytes = parseInt(response.headers.get("Content-Length"));
let bytesRead = 0; // How many bytes received so far
let reader = response.body.getReader(); // Read bytes with this function
let decoder = new TextDecoder("utf-8"); // For converting bytes to text
let body = ""; // Text read so far
while(true) { // Loop until we exit below
let {done, value} = await reader.read(); // Read a chunk
if (value) { // If we got a byte array:
if (processChunk) { // Process the bytes if
let processed = processChunk(value); // a callback was passed.
if (processed) {
body += processed;
}
} else { // Otherwise, convert bytes
body += decoder.decode(value, {stream: true}); // to text.
}
if (reportProgress) { // If a progress callback was
bytesRead += value.length; // passed, then call it
reportProgress(bytesRead, bytesRead / expectedBytes);
}
}
if (done) { // If this is the last chunk,
break; // exit the loop
}
}
return body; // Return the body text we accumulated
}