Skip to content

Commit 4e49f1e

Browse files
committed
Use functional composition to increase code reuse
1 parent 49a65fd commit 4e49f1e

File tree

2 files changed

+41
-87
lines changed

2 files changed

+41
-87
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616
"require": {
1717
"php": ">=5.3",
1818
"react/event-loop": "0.4.*|0.3.*",
19-
"react/promise": "~2.0|~1.0"
19+
"react/promise": "~2.0|~1.1"
2020
}
2121
}

src/functions.php

Lines changed: 40 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use React\Promise\CancellablePromiseInterface;
88
use UnderflowException;
99
use Exception;
10+
use React\Promise;
1011

1112
/**
1213
* wait/sleep for $time seconds
@@ -80,54 +81,28 @@ function ($error) use (&$exception, &$wait, $loop) {
8081
*/
8182
function awaitAny(array $promises, LoopInterface $loop)
8283
{
83-
$wait = count($promises);
84-
$value = null;
85-
$success = false;
86-
87-
foreach ($promises as $key => $promise) {
88-
/* @var $promise PromiseInterface */
89-
$promise->then(
90-
function ($return) use (&$value, &$wait, &$success, $promises, $loop) {
91-
if (!$wait) {
92-
// only store first promise value
93-
return;
94-
}
95-
$value = $return;
96-
$wait = 0;
97-
$success = true;
98-
99-
// cancel all remaining promises
100-
foreach ($promises as $promise) {
101-
if ($promise instanceof CancellablePromiseInterface) {
102-
$promise->cancel();
103-
}
104-
}
105-
106-
$loop->stop();
107-
},
108-
function ($e) use (&$wait, $loop) {
109-
if ($wait) {
110-
// count number of promises to await
111-
// cancelling promises will reject all remaining ones, ignore this
112-
--$wait;
113-
114-
if (!$wait) {
115-
$loop->stop();
116-
}
117-
}
118-
}
119-
);
120-
}
84+
try {
85+
// Promise\any() does not cope with an empty input array, so reject this here
86+
if (!$promises) {
87+
throw new UnderflowException('Empty input array');
88+
}
12189

122-
while ($wait) {
123-
$loop->run();
124-
}
90+
$ret = await(Promise\any($promises)->then(null, function () {
91+
// rejects with an array of rejection reasons => reject with Exception instead
92+
throw new Exception('All promises rejected');
93+
}), $loop);
94+
} catch (Exception $e) {
95+
// if the above throws, then ALL promises are already rejected
96+
// (attention: this does not apply once timeout comes into play)
12597

126-
if (!$success) {
127-
throw new UnderflowException('No promise could resolve');
98+
throw new UnderflowException('No promise could resolve', 0, $e);
12899
}
129100

130-
return $value;
101+
// if we reach this, then ANY of the given promises resolved
102+
// => try to cancel all promises (settled ones will be ignored anyway)
103+
_cancelAllPromises($promises);
104+
105+
return $ret;
131106
}
132107

133108
/**
@@ -147,49 +122,28 @@ function ($e) use (&$wait, $loop) {
147122
*/
148123
function awaitAll(array $promises, LoopInterface $loop)
149124
{
150-
$wait = count($promises);
151-
$exception = null;
152-
$values = array();
153-
154-
foreach ($promises as $key => $promise) {
155-
/* @var $promise PromiseInterface */
156-
$promise->then(
157-
function ($value) use (&$values, $key, &$wait, $loop) {
158-
$values[$key] = $value;
159-
--$wait;
160-
161-
if (!$wait) {
162-
$loop->stop();
163-
}
164-
},
165-
function ($e) use ($promises, &$exception, &$wait, $loop) {
166-
if (!$wait) {
167-
// cancelling promises will reject all remaining ones, only store first error
168-
return;
169-
}
170-
171-
$exception = $e;
172-
$wait = 0;
173-
174-
// cancel all remaining promises
175-
foreach ($promises as $promise) {
176-
if ($promise instanceof CancellablePromiseInterface) {
177-
$promise->cancel();
178-
}
179-
}
180-
181-
$loop->stop();
182-
}
183-
);
184-
}
185-
186-
while ($wait) {
187-
$loop->run();
125+
try {
126+
return await(Promise\all($promises), $loop);
127+
} catch (Exception $e) {
128+
// ANY of the given promises rejected
129+
// => try to cancel all promises (rejected ones will be ignored anyway)
130+
_cancelAllPromises($promises);
131+
132+
throw $e;
188133
}
134+
}
189135

190-
if ($exception !== null) {
191-
throw $exception;
136+
/**
137+
* internal helper function used to iterate over an array of Promise instances and cancel() each
138+
*
139+
* @internal
140+
* @param array $promises
141+
*/
142+
function _cancelAllPromises(array $promises)
143+
{
144+
foreach ($promises as $promise) {
145+
if ($promise instanceof CancellablePromiseInterface) {
146+
$promise->cancel();
147+
}
192148
}
193-
194-
return $values;
195149
}

0 commit comments

Comments
 (0)