Skip to content

Commit 6981c78

Browse files
committed
Improve await() in main to avoid unneeded futureTick() calls
1 parent 27f0027 commit 6981c78

File tree

3 files changed

+72
-2
lines changed

3 files changed

+72
-2
lines changed

src/SimpleFiber.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ public function __construct()
2020
public function resume(mixed $value): void
2121
{
2222
if ($this->fiber === null) {
23-
Loop::futureTick(static fn() => \Fiber::suspend(static fn() => $value));
23+
if (\Fiber::getCurrent() !== self::$scheduler) {
24+
Loop::futureTick(static fn() => \Fiber::suspend(static fn() => $value));
25+
} else {
26+
\Fiber::suspend(static fn() => $value);
27+
}
2428
return;
2529
}
2630

@@ -30,7 +34,11 @@ public function resume(mixed $value): void
3034
public function throw(\Throwable $throwable): void
3135
{
3236
if ($this->fiber === null) {
33-
Loop::futureTick(static fn() => \Fiber::suspend(static fn() => throw $throwable));
37+
if (\Fiber::getCurrent() !== self::$scheduler) {
38+
Loop::futureTick(static fn() => \Fiber::suspend(static fn() => throw $throwable));
39+
} else {
40+
\Fiber::suspend(static fn() => throw $throwable);
41+
}
3442
return;
3543
}
3644

tests/AsyncTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,22 @@ public function testAsyncReturnsPromiseThatFulfillsWithValueWhenCallbackReturnsA
143143
$this->assertEquals(42, $value);
144144
}
145145

146+
public function testAsyncReturnsPromiseThatRejectsWithExeptionWhenCallbackThrowsAfterAwaitingPromise()
147+
{
148+
$promise = async(function () {
149+
$promise = new Promise(function ($_, $reject) {
150+
Loop::addTimer(0.001, fn () => $reject(new \RuntimeException('Foo', 42)));
151+
});
152+
153+
return await($promise);
154+
})();
155+
156+
$this->expectException(\RuntimeException::class);
157+
$this->expectExceptionMessage('Foo');
158+
$this->expectExceptionCode(42);
159+
await($promise);
160+
}
161+
146162
public function testAsyncReturnsPromiseThatFulfillsWithValueWhenCallbackReturnsAfterAwaitingTwoConcurrentPromises()
147163
{
148164
$promise1 = async(function () {

tests/AwaitTest.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use React;
66
use React\EventLoop\Loop;
7+
use React\Promise\Deferred;
78
use React\Promise\Promise;
89

910
class AwaitTest extends TestCase
@@ -43,6 +44,30 @@ public function testAwaitThrowsExceptionWithoutRunningLoop(callable $await)
4344
}
4445
}
4546

47+
/**
48+
* @dataProvider provideAwaiters
49+
*/
50+
public function testAwaitThrowsExceptionImmediatelyWhenPromiseIsRejected(callable $await)
51+
{
52+
$deferred = new Deferred();
53+
54+
$ticks = 0;
55+
Loop::futureTick(function () use (&$ticks) {
56+
++$ticks;
57+
Loop::futureTick(function () use (&$ticks) {
58+
++$ticks;
59+
});
60+
});
61+
62+
Loop::futureTick(fn() => $deferred->reject(new \RuntimeException()));
63+
64+
try {
65+
$await($deferred->promise());
66+
} catch (\RuntimeException $e) {
67+
$this->assertEquals(1, $ticks);
68+
}
69+
}
70+
4671
/**
4772
* @dataProvider provideAwaiters
4873
*/
@@ -130,6 +155,27 @@ public function testAwaitReturnsValueImmediatelyWithoutRunningLoop(callable $awa
130155
$this->assertTrue($now);
131156
}
132157

158+
/**
159+
* @dataProvider provideAwaiters
160+
*/
161+
public function testAwaitReturnsValueImmediatelyWhenPromiseIsFulfilled(callable $await)
162+
{
163+
$deferred = new Deferred();
164+
165+
$ticks = 0;
166+
Loop::futureTick(function () use (&$ticks) {
167+
++$ticks;
168+
Loop::futureTick(function () use (&$ticks) {
169+
++$ticks;
170+
});
171+
});
172+
173+
Loop::futureTick(fn() => $deferred->resolve(42));
174+
175+
$this->assertEquals(42, $await($deferred->promise()));
176+
$this->assertEquals(1, $ticks);
177+
}
178+
133179
/**
134180
* @dataProvider provideAwaiters
135181
*/

0 commit comments

Comments
 (0)