@@ -68,36 +68,45 @@ function reject(\Throwable $reason): PromiseInterface
6868 * will be an array containing the resolution values of each of the items in
6969 * `$promisesOrValues`.
7070 *
71- * @param array $promisesOrValues
71+ * @param iterable $promisesOrValues
7272 * @return PromiseInterface
7373 */
74- function all (array $ promisesOrValues ): PromiseInterface
74+ function all (iterable $ promisesOrValues ): PromiseInterface
7575{
76- if (!$ promisesOrValues ) {
77- return resolve ([]);
78- }
79-
8076 $ cancellationQueue = new Internal \CancellationQueue ();
8177
8278 return new Promise (function ($ resolve , $ reject ) use ($ promisesOrValues , $ cancellationQueue ): void {
83- $ toResolve = \count ($ promisesOrValues );
79+ $ toResolve = 0 ;
80+ $ continue = true ;
8481 $ values = [];
8582
8683 foreach ($ promisesOrValues as $ i => $ promiseOrValue ) {
8784 $ cancellationQueue ->enqueue ($ promiseOrValue );
8885 $ values [$ i ] = null ;
86+ ++$ toResolve ;
87+
88+ resolve ($ promiseOrValue )->then (
89+ function ($ value ) use ($ i , &$ values , &$ toResolve , &$ continue , $ resolve ): void {
90+ $ values [$ i ] = $ value ;
91+
92+ if (0 === --$ toResolve && !$ continue ) {
93+ $ resolve ($ values );
94+ }
95+ },
96+ function (\Throwable $ reason ) use (&$ continue , $ reject ): void {
97+ $ continue = false ;
98+ $ reject ($ reason );
99+ }
100+ );
101+
102+ if (!$ continue ) {
103+ break ;
104+ }
105+ }
89106
90- resolve ($ promiseOrValue )
91- ->then (
92- function ($ mapped ) use ($ i , &$ values , &$ toResolve , $ resolve ): void {
93- $ values [$ i ] = $ mapped ;
94-
95- if (0 === --$ toResolve ) {
96- $ resolve ($ values );
97- }
98- },
99- $ reject
100- );
107+ $ continue = false ;
108+ if ($ toResolve === 0 ) {
109+ $ resolve ($ values );
101110 }
102111 }, $ cancellationQueue );
103112}
@@ -109,23 +118,26 @@ function ($mapped) use ($i, &$values, &$toResolve, $resolve): void {
109118 * The returned promise will become **infinitely pending** if `$promisesOrValues`
110119 * contains 0 items.
111120 *
112- * @param array $promisesOrValues
121+ * @param iterable $promisesOrValues
113122 * @return PromiseInterface
114123 */
115- function race (array $ promisesOrValues ): PromiseInterface
124+ function race (iterable $ promisesOrValues ): PromiseInterface
116125{
117- if (!$ promisesOrValues ) {
118- return new Promise (function (): void {});
119- }
120-
121126 $ cancellationQueue = new Internal \CancellationQueue ();
122127
123128 return new Promise (function ($ resolve , $ reject ) use ($ promisesOrValues , $ cancellationQueue ): void {
129+ $ continue = true ;
130+
124131 foreach ($ promisesOrValues as $ promiseOrValue ) {
125132 $ cancellationQueue ->enqueue ($ promiseOrValue );
126133
127- resolve ($ promiseOrValue )
128- ->then ($ resolve , $ reject );
134+ resolve ($ promiseOrValue )->then ($ resolve , $ reject )->finally (function () use (&$ continue ): void {
135+ $ continue = false ;
136+ });
137+
138+ if (!$ continue ) {
139+ break ;
140+ }
129141 }
130142 }, $ cancellationQueue );
131143}
@@ -141,53 +153,54 @@ function race(array $promisesOrValues): PromiseInterface
141153 * The returned promise will also reject with a `React\Promise\Exception\LengthException`
142154 * if `$promisesOrValues` contains 0 items.
143155 *
144- * @param array $promisesOrValues
156+ * @param iterable $promisesOrValues
145157 * @return PromiseInterface
146158 */
147- function any (array $ promisesOrValues ): PromiseInterface
159+ function any (iterable $ promisesOrValues ): PromiseInterface
148160{
149- $ len = \count ($ promisesOrValues );
150-
151- if (!$ promisesOrValues ) {
152- return reject (
153- new Exception \LengthException (
154- \sprintf (
155- 'Input array must contain at least 1 item but contains only %s item%s. ' ,
156- $ len ,
157- 1 === $ len ? '' : 's '
158- )
159- )
160- );
161- }
162-
163161 $ cancellationQueue = new Internal \CancellationQueue ();
164162
165- return new Promise (function ($ resolve , $ reject ) use ($ len , $ promisesOrValues , $ cancellationQueue ): void {
166- $ toReject = $ len ;
167- $ reasons = [];
163+ return new Promise (function ($ resolve , $ reject ) use ($ promisesOrValues , $ cancellationQueue ): void {
164+ $ toReject = 0 ;
165+ $ continue = true ;
166+ $ reasons = [];
168167
169168 foreach ($ promisesOrValues as $ i => $ promiseOrValue ) {
170- $ fulfiller = function ($ val ) use ($ resolve ): void {
171- $ resolve ($ val );
172- };
173-
174- $ rejecter = function (\Throwable $ reason ) use ($ i , &$ reasons , &$ toReject , $ reject ): void {
175- $ reasons [$ i ] = $ reason ;
176-
177- if (0 === --$ toReject ) {
178- $ reject (
179- new CompositeException (
169+ $ cancellationQueue ->enqueue ($ promiseOrValue );
170+ ++$ toReject ;
171+
172+ resolve ($ promiseOrValue )->then (
173+ function ($ value ) use ($ resolve , &$ continue ): void {
174+ $ continue = false ;
175+ $ resolve ($ value );
176+ },
177+ function (\Throwable $ reason ) use ($ i , &$ reasons , &$ toReject , $ reject , &$ continue ): void {
178+ $ reasons [$ i ] = $ reason ;
179+
180+ if (0 === --$ toReject && !$ continue ) {
181+ $ reject (new CompositeException (
180182 $ reasons ,
181183 'All promises rejected. '
182- )
183- );
184+ ));
185+ }
184186 }
185- } ;
187+ ) ;
186188
187- $ cancellationQueue ->enqueue ($ promiseOrValue );
189+ if (!$ continue ) {
190+ break ;
191+ }
192+ }
188193
189- resolve ($ promiseOrValue )
190- ->then ($ fulfiller , $ rejecter );
194+ $ continue = false ;
195+ if ($ toReject === 0 && !$ reasons ) {
196+ $ reject (new Exception \LengthException (
197+ 'Must contain at least 1 item but contains only 0 items. '
198+ ));
199+ } elseif ($ toReject === 0 ) {
200+ $ reject (new CompositeException (
201+ $ reasons ,
202+ 'All promises rejected. '
203+ ));
191204 }
192205 }, $ cancellationQueue );
193206}
0 commit comments