@@ -439,63 +439,76 @@ function createBlobReaderStream(reader) {
439439 // There really should only be one read at a time so using an
440440 // array here is purely defensive.
441441 this . pendingPulls = [ ] ;
442+ // Register a wakeup callback that the C++ side can invoke
443+ // when new data is available after a STATUS_BLOCK.
444+ reader . setWakeup ( ( ) => {
445+ if ( this . pendingPulls . length > 0 ) {
446+ this . readNext ( c ) ;
447+ }
448+ } ) ;
442449 } ,
443450 pull ( c ) {
444451 const { promise, resolve, reject } = PromiseWithResolvers ( ) ;
445452 this . pendingPulls . push ( { resolve, reject } ) ;
446- const readNext = ( ) => {
447- reader . pull ( ( status , buffer ) => {
448- // If pendingPulls is empty here, the stream had to have
449- // been canceled, and we don't really care about the result.
450- // We can simply exit.
451- if ( this . pendingPulls . length === 0 ) {
452- return ;
453- }
454- if ( status === 0 ) {
455- // EOS
456- c . close ( ) ;
457- // This is to signal the end for byob readers
458- // see https://streams.spec.whatwg.org/#example-rbs-pull
459- c . byobRequest ?. respond ( 0 ) ;
460- const pending = this . pendingPulls . shift ( ) ;
461- pending . resolve ( ) ;
462- return ;
463- } else if ( status < 0 ) {
464- // The read could fail for many different reasons when reading
465- // from a non-memory resident blob part (e.g. file-backed blob).
466- // The error details the system error code.
467- const error = lazyDOMException ( 'The blob could not be read' , 'NotReadableError' ) ;
468- const pending = this . pendingPulls . shift ( ) ;
469- c . error ( error ) ;
470- pending . reject ( error ) ;
453+ this . readNext ( c ) ;
454+ return promise ;
455+ } ,
456+ readNext ( c ) {
457+ reader . pull ( ( status , buffer ) => {
458+ // If pendingPulls is empty here, the stream had to have
459+ // been canceled, and we don't really care about the result.
460+ // We can simply exit.
461+ if ( this . pendingPulls . length === 0 ) {
462+ return ;
463+ }
464+ if ( status === 0 ) {
465+ // EOS
466+ c . close ( ) ;
467+ // This is to signal the end for byob readers
468+ // see https://streams.spec.whatwg.org/#example-rbs-pull
469+ c . byobRequest ?. respond ( 0 ) ;
470+ const pending = this . pendingPulls . shift ( ) ;
471+ pending . resolve ( ) ;
472+ return ;
473+ } else if ( status < 0 ) {
474+ // The read could fail for many different reasons when reading
475+ // from a non-memory resident blob part (e.g. file-backed blob).
476+ // The error details the system error code.
477+ const error =
478+ lazyDOMException ( 'The blob could not be read' ,
479+ 'NotReadableError' ) ;
480+ const pending = this . pendingPulls . shift ( ) ;
481+ c . error ( error ) ;
482+ pending . reject ( error ) ;
483+ return ;
484+ } else if ( status === 2 ) {
485+ // STATUS_BLOCK: No data available yet. The wakeup callback
486+ // registered in start() will re-invoke readNext when data
487+ // arrives.
488+ return ;
489+ }
490+ // ReadableByteStreamController.enqueue errors if we submit a
491+ // 0-length buffer. We need to check for that here.
492+ if ( buffer !== undefined && buffer . byteLength !== 0 ) {
493+ c . enqueue ( new Uint8Array ( buffer ) ) ;
494+ }
495+ // We keep reading until we either reach EOS, some error, or
496+ // we hit the flow rate of the stream (c.desiredSize).
497+ // We use setImmediate here because we have to allow the event
498+ // loop to turn in order to process any pending i/o. Using
499+ // queueMicrotask won't allow the event loop to turn.
500+ setImmediate ( ( ) => {
501+ if ( c . desiredSize < 0 ) {
502+ // A manual backpressure check.
503+ if ( this . pendingPulls . length !== 0 ) {
504+ const pending = this . pendingPulls . shift ( ) ;
505+ pending . resolve ( ) ;
506+ }
471507 return ;
472508 }
473- // ReadableByteStreamController.enqueue errors if we submit a 0-length
474- // buffer. We need to check for that here.
475- if ( buffer !== undefined && buffer . byteLength !== 0 ) {
476- c . enqueue ( new Uint8Array ( buffer ) ) ;
477- }
478- // We keep reading until we either reach EOS, some error, or we
479- // hit the flow rate of the stream (c.desiredSize).
480- // We use set immediate here because we have to allow the event
481- // loop to turn in order to process any pending i/o. Using
482- // queueMicrotask won't allow the event loop to turn.
483- setImmediate ( ( ) => {
484- if ( c . desiredSize < 0 ) {
485- // A manual backpressure check.
486- if ( this . pendingPulls . length !== 0 ) {
487- // A case of waiting pull finished (= not yet canceled)
488- const pending = this . pendingPulls . shift ( ) ;
489- pending . resolve ( ) ;
490- }
491- return ;
492- }
493- readNext ( ) ;
494- } ) ;
509+ this . readNext ( c ) ;
495510 } ) ;
496- } ;
497- readNext ( ) ;
498- return promise ;
511+ } ) ;
499512 } ,
500513 cancel ( reason ) {
501514 // Reject any currently pending pulls here.
0 commit comments