@@ -261,6 +261,7 @@ function copyPrototype(src, dest, prefix) {
261261/* eslint-enable node-core/prefer-primordials */
262262
263263const {
264+ Array : ArrayConstructor ,
264265 ArrayPrototypeForEach,
265266 ArrayPrototypeMap,
266267 FinalizationRegistry,
@@ -272,6 +273,7 @@ const {
272273 ObjectSetPrototypeOf,
273274 Promise,
274275 PromisePrototypeThen,
276+ PromiseResolve,
275277 ReflectApply,
276278 ReflectConstruct,
277279 ReflectSet,
@@ -466,9 +468,10 @@ const arrayToSafePromiseIterable = (promises, mapFn) =>
466468 ) ;
467469
468470/**
469- * @param {Promise<any>[] } promises
470- * @param {(v: Promise<any>, k: number) => Promise<any> } [mapFn]
471- * @returns {Promise<any[]> }
471+ * @template T,U
472+ * @param {Array<T | PromiseLike<T>> } promises
473+ * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U> } [mapFn]
474+ * @returns {Promise<Awaited<U>[]> }
472475 */
473476primordials . SafePromiseAll = ( promises , mapFn ) =>
474477 // Wrapping on a new Promise is necessary to not expose the SafePromise
@@ -478,8 +481,56 @@ primordials.SafePromiseAll = (promises, mapFn) =>
478481 ) ;
479482
480483/**
481- * @param {Promise<any>[] } promises
482- * @param {(v: Promise<any>, k: number) => Promise<any> } [mapFn]
484+ * Should only be used for internal functions, this would produce similar
485+ * results as `Promise.all` but without prototype pollution, and the return
486+ * value is not a genuine Array but an array-like object.
487+ * @template T,U
488+ * @param {ArrayLike<T | PromiseLike<T>> } promises
489+ * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U> } [mapFn]
490+ * @returns {Promise<ArrayLike<Awaited<U>>> }
491+ */
492+ primordials . SafePromiseAllReturnArrayLike = ( promises , mapFn ) =>
493+ new Promise ( ( resolve , reject ) => {
494+ const { length } = promises ;
495+
496+ const returnVal = ArrayConstructor ( length ) ;
497+ ObjectSetPrototypeOf ( returnVal , null ) ;
498+ if ( length === 0 ) resolve ( returnVal ) ;
499+
500+ let pendingPromises = length ;
501+ for ( let i = 0 ; i < length ; i ++ ) {
502+ const promise = mapFn != null ? mapFn ( promises [ i ] , i ) : promises [ i ] ;
503+ PromisePrototypeThen ( PromiseResolve ( promise ) , ( result ) => {
504+ returnVal [ i ] = result ;
505+ if ( -- pendingPromises === 0 ) resolve ( returnVal ) ;
506+ } , reject ) ;
507+ }
508+ } ) ;
509+
510+ /**
511+ * Should only be used when we only care about waiting for all the promises to
512+ * resolve, not what value they resolve to.
513+ * @template T,U
514+ * @param {ArrayLike<T | PromiseLike<T>> } promises
515+ * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U> } [mapFn]
516+ * @returns {Promise<void> }
517+ */
518+ primordials . SafePromiseAllReturnVoid = ( promises , mapFn ) =>
519+ new Promise ( ( resolve , reject ) => {
520+ let pendingPromises = promises . length ;
521+ if ( pendingPromises === 0 ) resolve ( ) ;
522+ for ( let i = 0 ; i < promises . length ; i ++ ) {
523+ const promise = mapFn != null ? mapFn ( promises [ i ] , i ) : promises [ i ] ;
524+ PromisePrototypeThen ( PromiseResolve ( promise ) , ( ) => {
525+ if ( -- pendingPromises === 0 ) resolve ( ) ;
526+ } , reject ) ;
527+ }
528+ } ) ;
529+
530+ /**
531+ * @template T,U
532+ * @param {Array<T|PromiseLike<T>> } promises
533+ * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U> } [mapFn]
483534 * @returns {Promise<PromiseSettledResult<any>[]> }
484535 */
485536primordials . SafePromiseAllSettled = ( promises , mapFn ) =>
@@ -490,9 +541,28 @@ primordials.SafePromiseAllSettled = (promises, mapFn) =>
490541 ) ;
491542
492543/**
493- * @param {Promise<any>[] } promises
494- * @param {(v: Promise<any>, k: number) => Promise<any> } [mapFn]
495- * @returns {Promise<any> }
544+ * Should only be used when we only care about waiting for all the promises to
545+ * settle, not what value they resolve or reject to.
546+ * @template T,U
547+ * @param {ArrayLike<T|PromiseLike<T>> } promises
548+ * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U> } [mapFn]
549+ * @returns {Promise<void> }
550+ */
551+ primordials . SafePromiseAllSettledReturnVoid = async ( promises , mapFn ) => {
552+ for ( let i = 0 ; i < promises . length ; i ++ ) {
553+ try {
554+ await ( mapFn != null ? mapFn ( promises [ i ] , i ) : promises [ i ] ) ;
555+ } catch {
556+ // In all settled, we can ignore errors.
557+ }
558+ }
559+ } ;
560+
561+ /**
562+ * @template T,U
563+ * @param {Array<T|PromiseLike<T>> } promises
564+ * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U> } [mapFn]
565+ * @returns {Promise<Awaited<U>> }
496566 */
497567primordials . SafePromiseAny = ( promises , mapFn ) =>
498568 // Wrapping on a new Promise is necessary to not expose the SafePromise
@@ -502,9 +572,10 @@ primordials.SafePromiseAny = (promises, mapFn) =>
502572 ) ;
503573
504574/**
505- * @param {Promise<any>[] } promises
506- * @param {(v: Promise<any>, k: number) => Promise<any> } [mapFn]
507- * @returns {Promise<any> }
575+ * @template T,U
576+ * @param {Array<T|PromiseLike<T>> } promises
577+ * @param {(v: T|PromiseLike<T>, k: number) => U|PromiseLike<U> } [mapFn]
578+ * @returns {Promise<Awaited<U>> }
508579 */
509580primordials . SafePromiseRace = ( promises , mapFn ) =>
510581 // Wrapping on a new Promise is necessary to not expose the SafePromise
0 commit comments