88use UnderflowException ;
99use Exception ;
1010use React \Promise ;
11+ use React \Promise \Timer ;
12+ use React \Promise \Timer \TimeoutException ;
1113
1214/**
1315 * wait/sleep for $time seconds
1719 */
1820function sleep ($ time , LoopInterface $ loop )
1921{
20- $ wait = true ;
21- $ loop ->addTimer ($ time , function () use ($ loop , &$ wait ) {
22- $ loop ->stop ();
23- $ wait = false ;
24- });
25-
26- do {
27- $ loop ->run ();
28- } while ($ wait );
22+ await (Timer \resolve ($ time , $ loop ), $ loop );
2923}
3024
3125/**
3226 * block waiting for the given $promise to resolve
3327 *
28+ * Once the promise is resolved, this will return whatever the promise resolves to.
29+ *
30+ * Once the promise is rejected, this will throw whatever the promise rejected with.
31+ *
32+ * If no $timeout is given and the promise stays pending, then this will
33+ * potentially wait/block forever until the promise is settled.
34+ *
35+ * If a $timeout is given and the promise is still pending once the timeout
36+ * triggers, this will cancel() the promise and throw a `TimeoutException`.
37+ *
3438 * @param PromiseInterface $promise
3539 * @param LoopInterface $loop
40+ * @param null|float $timeout (optional) maximum timeout in seconds or null=wait forever
3641 * @return mixed returns whatever the promise resolves to
3742 * @throws Exception when the promise is rejected
43+ * @throws TimeoutException if the $timeout is given and triggers
3844 */
39- function await (PromiseInterface $ promise , LoopInterface $ loop )
45+ function await (PromiseInterface $ promise , LoopInterface $ loop, $ timeout = null )
4046{
4147 $ wait = true ;
4248 $ resolved = null ;
4349 $ exception = null ;
4450
51+ if ($ timeout !== null ) {
52+ $ promise = Timer \timeout ($ promise , $ timeout , $ loop );
53+ }
54+
4555 $ promise ->then (
4656 function ($ c ) use (&$ resolved , &$ wait , $ loop ) {
4757 $ resolved = $ c ;
@@ -74,12 +84,20 @@ function ($error) use (&$exception, &$wait, $loop) {
7484 *
7585 * If ALL promises fail to resolve, this will fail and throw an Exception.
7686 *
87+ * If no $timeout is given and either promise stays pending, then this will
88+ * potentially wait/block forever until the last promise is settled.
89+ *
90+ * If a $timeout is given and either promise is still pending once the timeout
91+ * triggers, this will cancel() all pending promises and throw a `TimeoutException`.
92+ *
7793 * @param array $promises
7894 * @param LoopInterface $loop
95+ * @param null|float $timeout (optional) maximum timeout in seconds or null=wait forever
7996 * @return mixed returns whatever the first promise resolves to
8097 * @throws Exception if ALL promises are rejected
98+ * @throws TimeoutException if the $timeout is given and triggers
8199 */
82- function awaitAny (array $ promises , LoopInterface $ loop )
100+ function awaitAny (array $ promises , LoopInterface $ loop, $ timeout = null )
83101{
84102 try {
85103 // Promise\any() does not cope with an empty input array, so reject this here
@@ -90,10 +108,17 @@ function awaitAny(array $promises, LoopInterface $loop)
90108 $ ret = await (Promise \any ($ promises )->then (null , function () {
91109 // rejects with an array of rejection reasons => reject with Exception instead
92110 throw new Exception ('All promises rejected ' );
93- }), $ loop );
111+ }), $ loop , $ timeout );
112+ } catch (TimeoutException $ e ) {
113+ // the timeout fired
114+ // => try to cancel all promises (rejected ones will be ignored anyway)
115+ _cancelAllPromises ($ promises );
116+
117+ throw $ e ;
94118 } catch (Exception $ e ) {
95119 // if the above throws, then ALL promises are already rejected
96- // (attention: this does not apply once timeout comes into play)
120+ // => try to cancel all promises (rejected ones will be ignored anyway)
121+ _cancelAllPromises ($ promises );
97122
98123 throw new UnderflowException ('No promise could resolve ' , 0 , $ e );
99124 }
@@ -115,17 +140,25 @@ function awaitAny(array $promises, LoopInterface $loop)
115140 * If ANY promise fails to resolve, this will try to cancel() all
116141 * remaining promises and throw an Exception.
117142 *
143+ * If no $timeout is given and either promise stays pending, then this will
144+ * potentially wait/block forever until the last promise is settled.
145+ *
146+ * If a $timeout is given and either promise is still pending once the timeout
147+ * triggers, this will cancel() all pending promises and throw a `TimeoutException`.
148+ *
118149 * @param array $promises
119150 * @param LoopInterface $loop
151+ * @param null|float $timeout (optional) maximum timeout in seconds or null=wait forever
120152 * @return array returns an array with whatever each promise resolves to
121153 * @throws Exception when ANY promise is rejected
154+ * @throws TimeoutException if the $timeout is given and triggers
122155 */
123- function awaitAll (array $ promises , LoopInterface $ loop )
156+ function awaitAll (array $ promises , LoopInterface $ loop, $ timeout = null )
124157{
125158 try {
126- return await (Promise \all ($ promises ), $ loop );
159+ return await (Promise \all ($ promises ), $ loop, $ timeout );
127160 } catch (Exception $ e ) {
128- // ANY of the given promises rejected
161+ // ANY of the given promises rejected or the timeout fired
129162 // => try to cancel all promises (rejected ones will be ignored anyway)
130163 _cancelAllPromises ($ promises );
131164
0 commit comments