6
6
MathMin,
7
7
ObjectDefineProperties,
8
8
ObjectDefineProperty,
9
- PromiseResolve,
10
9
PromiseReject,
11
- SafePromisePrototypeFinally ,
10
+ PromiseResolve ,
12
11
ReflectConstruct,
13
12
RegExpPrototypeExec,
14
13
RegExpPrototypeSymbolReplace,
@@ -22,7 +21,8 @@ const {
22
21
23
22
const {
24
23
createBlob : _createBlob ,
25
- FixedSizeBlobCopyJob,
24
+ createBlobFromFileHandle : _createBlobFromFileHandle ,
25
+ concat,
26
26
getDataObject,
27
27
} = internalBinding ( 'blob' ) ;
28
28
@@ -52,13 +52,13 @@ const {
52
52
const { inspect } = require ( 'internal/util/inspect' ) ;
53
53
54
54
const {
55
- AbortError,
56
55
codes : {
57
56
ERR_INVALID_ARG_TYPE ,
58
57
ERR_INVALID_ARG_VALUE ,
59
58
ERR_INVALID_THIS ,
60
59
ERR_BUFFER_TOO_LARGE ,
61
- }
60
+ } ,
61
+ errnoException,
62
62
} = require ( 'internal/errors' ) ;
63
63
64
64
const {
@@ -67,13 +67,8 @@ const {
67
67
} = require ( 'internal/validators' ) ;
68
68
69
69
const kHandle = Symbol ( 'kHandle' ) ;
70
- const kState = Symbol ( 'kState' ) ;
71
- const kIndex = Symbol ( 'kIndex' ) ;
72
70
const kType = Symbol ( 'kType' ) ;
73
71
const kLength = Symbol ( 'kLength' ) ;
74
- const kArrayBufferPromise = Symbol ( 'kArrayBufferPromise' ) ;
75
-
76
- const kMaxChunkSize = 65536 ;
77
72
78
73
const disallowedTypeCharacters = / [ ^ \u{0020} - \u{007E} ] / u;
79
74
@@ -266,40 +261,28 @@ class Blob {
266
261
if ( ! isBlob ( this ) )
267
262
return PromiseReject ( new ERR_INVALID_THIS ( 'Blob' ) ) ;
268
263
269
- // If there's already a promise in flight for the content,
270
- // reuse it, but only while it's in flight. After the cached
271
- // promise resolves it will be cleared, allowing it to be
272
- // garbage collected as soon as possible.
273
- if ( this [ kArrayBufferPromise ] )
274
- return this [ kArrayBufferPromise ] ;
275
-
276
- const job = new FixedSizeBlobCopyJob ( this [ kHandle ] ) ;
277
-
278
- const ret = job . run ( ) ;
279
-
280
- // If the job returns a value immediately, the ArrayBuffer
281
- // was generated synchronously and should just be returned
282
- // directly.
283
- if ( ret !== undefined )
284
- return PromiseResolve ( ret ) ;
264
+ if ( this . size === 0 ) {
265
+ return PromiseResolve ( new ArrayBuffer ( 0 ) ) ;
266
+ }
285
267
286
- const {
287
- promise,
288
- resolve,
289
- reject,
290
- } = createDeferredPromise ( ) ;
291
-
292
- job . ondone = ( err , ab ) => {
293
- if ( err !== undefined )
294
- return reject ( new AbortError ( undefined , { cause : err } ) ) ;
295
- resolve ( ab ) ;
268
+ const { promise, resolve } = createDeferredPromise ( ) ;
269
+ const reader = this [ kHandle ] . getReader ( ) ;
270
+ const buffers = [ ] ;
271
+ const readNext = ( ) => {
272
+ reader . pull ( ( status , buffer ) => {
273
+ if ( status === - 1 ) {
274
+ // EOS, concat & resolve
275
+ // buffer should be undefined here
276
+ resolve ( concat ( buffers ) ) ;
277
+ return ;
278
+ }
279
+ if ( buffer !== undefined )
280
+ buffers . push ( buffer ) ;
281
+ readNext ( ) ;
282
+ } ) ;
296
283
} ;
297
- this [ kArrayBufferPromise ] =
298
- SafePromisePrototypeFinally (
299
- promise ,
300
- ( ) => this [ kArrayBufferPromise ] = undefined ) ;
301
-
302
- return this [ kArrayBufferPromise ] ;
284
+ readNext ( ) ;
285
+ return promise ;
303
286
}
304
287
305
288
/**
@@ -321,24 +304,57 @@ class Blob {
321
304
if ( ! isBlob ( this ) )
322
305
throw new ERR_INVALID_THIS ( 'Blob' ) ;
323
306
324
- const self = this ;
307
+ if ( this . size === 0 ) {
308
+ return new lazyReadableStream ( {
309
+ start ( c ) { c . close ( ) ; }
310
+ } ) ;
311
+ }
312
+
313
+ const reader = this [ kHandle ] . getReader ( ) ;
325
314
return new lazyReadableStream ( {
326
- async start ( ) {
327
- this [ kState ] = await self . arrayBuffer ( ) ;
328
- this [ kIndex ] = 0 ;
315
+ start ( c ) {
316
+ // There really should only be one read at a time so using an
317
+ // array here is purely defensive.
318
+ this . pendingPulls = [ ] ;
329
319
} ,
330
-
331
- pull ( controller ) {
332
- if ( this [ kState ] . byteLength - this [ kIndex ] <= kMaxChunkSize ) {
333
- controller . enqueue ( new Uint8Array ( this [ kState ] , this [ kIndex ] ) ) ;
334
- controller . close ( ) ;
335
- this [ kState ] = undefined ;
336
- } else {
337
- controller . enqueue ( new Uint8Array ( this [ kState ] , this [ kIndex ] , kMaxChunkSize ) ) ;
338
- this [ kIndex ] += kMaxChunkSize ;
320
+ pull ( c ) {
321
+ const { promise, resolve, reject } = createDeferredPromise ( ) ;
322
+ this . pendingPulls . push ( { resolve, reject} ) ;
323
+ reader . pull ( ( status , buffer ) => {
324
+ // If pendingPulls is empty here, the stream had to have
325
+ // been canceled, and we don't really care about the result.
326
+ // we can simply exit.
327
+ if ( this . pendingPulls . length === 0 ) {
328
+ return ;
329
+ }
330
+ const pending = this . pendingPulls . shift ( ) ;
331
+ if ( status === - 1 || ( status === 0 && buffer === undefined ) ) {
332
+ // EOS
333
+ c . close ( ) ;
334
+ pending . resolve ( ) ;
335
+ return ;
336
+ } else if ( status < 0 ) {
337
+ const error = errnoException ( status , 'read' ) ;
338
+ c . error ( error ) ;
339
+ pending . reject ( error ) ;
340
+ return ;
341
+ }
342
+ c . enqueue ( new Uint8Array ( buffer ) ) ;
343
+ pending . resolve ( ) ;
344
+ } ) ;
345
+ return promise ;
346
+ } ,
347
+ cancel ( reason ) {
348
+ // Reject any currently pending pulls here.
349
+ for ( const pending of this . pendingPulls ) {
350
+ pending . reject ( reason ) ;
339
351
}
352
+ this . pendingPulls = [ ] ;
340
353
}
341
- } ) ;
354
+ // We set the highWaterMark to 0 because we do not want the stream to
355
+ // start reading immediately on creation. We want it to wait until read
356
+ // is called.
357
+ } , new CountQueuingStrategy ( { highWaterMark : 0 } ) ) ;
342
358
}
343
359
}
344
360
@@ -406,10 +422,16 @@ function resolveObjectURL(url) {
406
422
}
407
423
}
408
424
425
+ function createBlobFromFileHandle ( handle ) {
426
+ const [ blob , length ] = _createBlobFromFileHandle ( handle ) ;
427
+ return createBlob ( blob , length ) ;
428
+ }
429
+
409
430
module . exports = {
410
431
Blob,
411
432
ClonedBlob,
412
433
createBlob,
434
+ createBlobFromFileHandle,
413
435
isBlob,
414
436
kHandle,
415
437
resolveObjectURL,
0 commit comments