@@ -47,7 +47,7 @@ const {
4747 toUint8Array,
4848} = require ( 'internal/streams/iter/utils' ) ;
4949
50- // Maximum number of chunks to yield per batch from from(Uint8Array[] ).
50+ // Maximum number of chunks to yield per batch from from()/fromSync( ).
5151// Bounds peak memory when arrays flow through transforms, which must
5252// allocate output for the entire batch at once.
5353const FROM_BATCH_SIZE = 128 ;
@@ -190,33 +190,66 @@ function isUint8ArrayBatch(value) {
190190 return true ;
191191}
192192
193+ function * yieldBoundedBatch ( batch ) {
194+ if ( batch . length === 0 ) {
195+ return ;
196+ }
197+ if ( batch . length <= FROM_BATCH_SIZE ) {
198+ yield batch ;
199+ return ;
200+ }
201+ for ( let i = 0 ; i < batch . length ; i += FROM_BATCH_SIZE ) {
202+ yield ArrayPrototypeSlice ( batch , i , i + FROM_BATCH_SIZE ) ;
203+ }
204+ }
205+
193206/**
194207 * Normalize a sync streamable source, yielding batches of Uint8Array.
195208 * @param {Iterable } source
196209 * @yields {Uint8Array[]}
197210 */
198211function * normalizeSyncSource ( source ) {
212+ let batch = [ ] ;
213+
199214 for ( const value of source ) {
200215 // Fast path 1: value is already a Uint8Array[] batch
201216 if ( isUint8ArrayBatch ( value ) ) {
202- if ( value . length > 0 ) {
203- yield value ;
217+ if ( batch . length > 0 ) {
218+ yield batch ;
219+ batch = [ ] ;
204220 }
221+ yield * yieldBoundedBatch ( value ) ;
205222 continue ;
206223 }
207224 // Fast path 2: value is a single Uint8Array (very common)
208225 if ( isUint8Array ( value ) ) {
209- yield [ value ] ;
226+ ArrayPrototypePush ( batch , value ) ;
227+ if ( batch . length === FROM_BATCH_SIZE ) {
228+ yield batch ;
229+ batch = [ ] ;
230+ }
210231 continue ;
211232 }
212233 // Slow path: normalize the value
213- const batch = [ ] ;
214- for ( const chunk of normalizeSyncValue ( value ) ) {
215- ArrayPrototypePush ( batch , chunk ) ;
216- }
217234 if ( batch . length > 0 ) {
218235 yield batch ;
236+ batch = [ ] ;
237+ }
238+ let valueBatch = [ ] ;
239+ for ( const chunk of normalizeSyncValue ( value ) ) {
240+ ArrayPrototypePush ( valueBatch , chunk ) ;
241+ if ( valueBatch . length === FROM_BATCH_SIZE ) {
242+ yield valueBatch ;
243+ valueBatch = [ ] ;
244+ }
219245 }
246+ if ( valueBatch . length > 0 ) {
247+ yield valueBatch ;
248+ }
249+ }
250+
251+ if ( batch . length > 0 ) {
252+ yield batch ;
220253 }
221254}
222255
@@ -329,36 +362,42 @@ async function* normalizeAsyncSource(source) {
329362 return ;
330363 }
331364
332- // Fall back to sync iteration - batch all sync values together
365+ // Fall back to sync iteration - batch sync values together with a bound.
333366 if ( isSyncIterable ( source ) ) {
334- const batch = [ ] ;
367+ let batch = [ ] ;
335368
336369 for ( const value of source ) {
337370 // Fast path 1: value is already a Uint8Array[] batch
338371 if ( isUint8ArrayBatch ( value ) ) {
339372 // Flush any accumulated batch first
340373 if ( batch . length > 0 ) {
341- yield ArrayPrototypeSlice ( batch ) ;
342- batch . length = 0 ;
343- }
344- if ( value . length > 0 ) {
345- yield value ;
374+ yield batch ;
375+ batch = [ ] ;
346376 }
377+ yield * yieldBoundedBatch ( value ) ;
347378 continue ;
348379 }
349380 // Fast path 2: value is a single Uint8Array (very common)
350381 if ( isUint8Array ( value ) ) {
351382 ArrayPrototypePush ( batch , value ) ;
383+ if ( batch . length === FROM_BATCH_SIZE ) {
384+ yield batch ;
385+ batch = [ ] ;
386+ }
352387 continue ;
353388 }
354389 // Slow path: normalize the value - must flush and yield individually
355390 if ( batch . length > 0 ) {
356- yield ArrayPrototypeSlice ( batch ) ;
357- batch . length = 0 ;
391+ yield batch ;
392+ batch = [ ] ;
358393 }
359- const asyncBatch = [ ] ;
394+ let asyncBatch = [ ] ;
360395 for await ( const chunk of normalizeAsyncValue ( value ) ) {
361396 ArrayPrototypePush ( asyncBatch , chunk ) ;
397+ if ( asyncBatch . length === FROM_BATCH_SIZE ) {
398+ yield asyncBatch ;
399+ asyncBatch = [ ] ;
400+ }
362401 }
363402 if ( asyncBatch . length > 0 ) {
364403 yield asyncBatch ;
0 commit comments