1- // https://www.npmjs.com/package/xhr-shim under MIT
1+ // Originally from https://www.npmjs.com/package/xhr-shim under MIT, heavily modified since
22
33/* global module */
44/* global EventTarget, AbortController, DOMException */
@@ -16,12 +16,51 @@ const sTimeout = Symbol("timeout");
1616const sTimedOut = Symbol ( "timedOut" ) ;
1717const sIsResponseText = Symbol ( "isResponseText" ) ;
1818
19+ // SO: https://stackoverflow.com/questions/49129643/how-do-i-merge-an-array-of-uint8arrays
20+ function mergeUint8Arrays ( ...arrays ) {
21+ const totalSize = arrays . reduce ( ( acc , e ) => acc + e . length , 0 ) ;
22+ const merged = new Uint8Array ( totalSize ) ;
23+
24+ arrays . forEach ( ( array , i , arrays ) => {
25+ const offset = arrays . slice ( 0 , i ) . reduce ( ( acc , e ) => acc + e . length , 0 ) ;
26+ merged . set ( array , offset ) ;
27+ } ) ;
28+
29+ return merged ;
30+ }
31+
32+ /**
33+ * Exposes incoming data
34+ * @this {XMLHttpRequest}
35+ * @param {Uint8Array } bytes
36+ */
37+ async function parseBody ( bytes ) {
38+ const responseType = this . responseType || "text" ;
39+ const textde = new TextDecoder ( ) ;
40+ const finalMIME = this [ sMIME ] || this [ sRespHeaders ] . get ( "content-type" ) || "text/plain" ;
41+ switch ( responseType ) {
42+ case "text" :
43+ this . response = textde . decode ( bytes )
44+ break ;
45+ case "blob" :
46+ this . response = new Blob ( [ bytes ] , { type : finalMIME } ) ;
47+ break ;
48+ case "arraybuffer" :
49+ this . response = bytes . buffer ;
50+ break ;
51+ case "json" :
52+ this . response = JSON . parse ( textde . decode ( bytes ) ) ;
53+ break ;
54+ }
55+ }
56+
1957const XMLHttpRequestShim = class XMLHttpRequest extends EventTarget {
2058 onreadystatechange ( ) {
2159
2260 }
2361
2462 set readyState ( value ) {
63+ if ( this [ sReadyState ] === value ) return ; // dont do anything if "value" is already the internal value
2564 this [ sReadyState ] = value ;
2665 this . dispatchEvent ( new Event ( "readystatechange" ) ) ;
2766 this . onreadystatechange ( new Event ( "readystatechange" ) ) ;
@@ -146,21 +185,26 @@ const XMLHttpRequestShim = class XMLHttpRequest extends EventTarget {
146185 this . status = resp . status ;
147186 this . statusText = resp . statusText ;
148187 this [ sRespHeaders ] = resp . headers ;
149- const finalMIME = this [ sMIME ] || this [ sRespHeaders ] . get ( "content-type" ) || "text/plain" ;
150- switch ( responseType ) {
151- case "text" :
152- this . response = await resp . text ( ) ;
153- break ;
154- case "blob" :
155- this . response = new Blob ( [ await resp . arrayBuffer ( ) ] , { type : finalMIME } ) ;
156- break ;
157- case "arraybuffer" :
158- this . response = await resp . arrayBuffer ( ) ;
159- break ;
160- case "json" :
161- this . response = await resp . json ( ) ;
162- break ;
188+ this . readyState = this . constructor . HEADERS_RECEIVED ;
189+
190+ if ( resp . headers . get ( "content-type" ) . includes ( "application/x-ndjson" ) || this . streamRequestBadForPerformance ) {
191+ let bytes = new Uint8Array ( ) ;
192+ for await ( const chunk of resp . body ) {
193+ this . readyState = this . constructor . LOADING ;
194+
195+ bytes = mergeUint8Arrays ( bytes , chunk ) ;
196+ parseBody . call ( this , bytes ) ;
197+ this [ sDispatch ] ( new CustomEvent ( "progress" ) ) ;
198+ }
199+ } else {
200+ const bytesChunks = [ ] ;
201+ for await ( const chunk of resp . body ) {
202+ bytesChunks . push ( chunk )
203+ }
204+ parseBody . call ( this , mergeUint8Arrays ( ...bytesChunks ) ) ;
163205 }
206+
207+
164208 this . readyState = this . constructor . DONE ;
165209 this [ sDispatch ] ( new CustomEvent ( "load" ) ) ;
166210 } , err => {
0 commit comments