Skip to content

Commit 42d86b7

Browse files
committed
Cancel pending promises in race/some/any once the output promise resolves
1 parent 383277b commit 42d86b7

4 files changed

Lines changed: 91 additions & 2 deletions

File tree

src/functions.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,18 @@ function race($promisesOrValues)
5151
foreach ($array as $promiseOrValue) {
5252
$cancellationQueue->enqueue($promiseOrValue);
5353

54+
$fulfiller = function ($value) use ($cancellationQueue, $resolve) {
55+
$cancellationQueue();
56+
$resolve($value);
57+
};
58+
59+
$rejecter = function ($reason) use ($cancellationQueue, $reject) {
60+
$cancellationQueue();
61+
$reject($reason);
62+
};
63+
5464
resolve($promiseOrValue)
55-
->done($resolve, $reject, $notify);
65+
->done($fulfiller, $rejecter, $notify);
5666
}
5767
}, $reject, $notify);
5868
}, $cancellationQueue);
@@ -86,14 +96,15 @@ function some($promisesOrValues, $howMany)
8696
$reasons = [];
8797

8898
foreach ($array as $i => $promiseOrValue) {
89-
$fulfiller = function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve) {
99+
$fulfiller = function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve, $cancellationQueue) {
90100
if ($toResolve < 1 || $toReject < 1) {
91101
return;
92102
}
93103

94104
$values[$i] = $val;
95105

96106
if (0 === --$toResolve) {
107+
$cancellationQueue();
97108
$resolve($values);
98109
}
99110
};

tests/FunctionAnyTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,4 +153,24 @@ public function shouldCancelInputArrayPromises()
153153

154154
any([$mock1, $mock2])->cancel();
155155
}
156+
157+
/** @test */
158+
public function shouldCancelOtherPendingInputArrayPromisesIfOnePromiseFulfills()
159+
{
160+
$mock = $this->createCallableMock();
161+
$mock
162+
->expects($this->never())
163+
->method('__invoke');
164+
165+
166+
$deferred = New Deferred($mock);
167+
$deferred->resolve();
168+
169+
$mock2 = $this->getMock('React\Promise\CancellablePromiseInterface');
170+
$mock2
171+
->expects($this->once())
172+
->method('cancel');
173+
174+
some([$deferred->promise(), $mock2], 1)->cancel();
175+
}
156176
}

tests/FunctionRaceTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,42 @@ public function shouldCancelInputArrayPromises()
160160

161161
race([$mock1, $mock2])->cancel();
162162
}
163+
164+
/** @test */
165+
public function shouldCancelOtherPendingInputArrayPromisesIfOnePromiseFulfills()
166+
{
167+
$mock = $this->createCallableMock();
168+
$mock
169+
->expects($this->never())
170+
->method('__invoke');
171+
172+
$deferred = New Deferred($mock);
173+
$deferred->resolve();
174+
175+
$mock2 = $this->getMock('React\Promise\CancellablePromiseInterface');
176+
$mock2
177+
->expects($this->once())
178+
->method('cancel');
179+
180+
race([$deferred->promise(), $mock2])->cancel();
181+
}
182+
183+
/** @test */
184+
public function shouldCancelOtherPendingInputArrayPromisesIfOnePromiseRejects()
185+
{
186+
$mock = $this->createCallableMock();
187+
$mock
188+
->expects($this->never())
189+
->method('__invoke');
190+
191+
$deferred = New Deferred($mock);
192+
$deferred->reject();
193+
194+
$mock2 = $this->getMock('React\Promise\CancellablePromiseInterface');
195+
$mock2
196+
->expects($this->once())
197+
->method('cancel');
198+
199+
race([$deferred->promise(), $mock2])->cancel();
200+
}
163201
}

tests/FunctionSomeTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,4 +165,24 @@ public function shouldCancelInputArrayPromises()
165165

166166
some([$mock1, $mock2], 1)->cancel();
167167
}
168+
169+
/** @test */
170+
public function shouldCancelOtherPendingInputArrayPromisesIfEnoughPromisesFulfill()
171+
{
172+
$mock = $this->createCallableMock();
173+
$mock
174+
->expects($this->never())
175+
->method('__invoke');
176+
177+
178+
$deferred = New Deferred($mock);
179+
$deferred->resolve();
180+
181+
$mock2 = $this->getMock('React\Promise\CancellablePromiseInterface');
182+
$mock2
183+
->expects($this->once())
184+
->method('cancel');
185+
186+
some([$deferred->promise(), $mock2], 1)->cancel();
187+
}
168188
}

0 commit comments

Comments
 (0)