Skip to content

Commit 584e5b0

Browse files
committed
Fast forward resolved/rejected promises with await
This makes `await`ing an already resolved promise significantly faster. Ported from: #18
1 parent c989ee1 commit 584e5b0

File tree

2 files changed

+40
-15
lines changed

2 files changed

+40
-15
lines changed

src/functions.php

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,20 @@
5353
function await(PromiseInterface $promise)
5454
{
5555
$wait = true;
56-
$resolved = null;
57-
$exception = null;
56+
$resolved = false;
5857
$rejected = false;
58+
$resolvedValue = null;
59+
$rejectedThrowable = null;
5960

6061
$promise->then(
61-
function ($c) use (&$resolved, &$wait) {
62-
$resolved = $c;
62+
function ($c) use (&$resolved, &$resolvedValue, &$wait) {
63+
$resolvedValue = $c;
64+
$resolved = true;
6365
$wait = false;
6466
Loop::stop();
6567
},
66-
function ($error) use (&$exception, &$rejected, &$wait) {
67-
$exception = $error;
68+
function ($error) use (&$rejected, &$rejectedThrowable, &$wait) {
69+
$rejectedThrowable = $error;
6870
$rejected = true;
6971
$wait = false;
7072
Loop::stop();
@@ -75,24 +77,40 @@ function ($error) use (&$exception, &$rejected, &$wait) {
7577
// argument does not show up in the stack trace in PHP 7+ only.
7678
$promise = null;
7779

80+
if ($rejected) {
81+
awaitThrow($rejectedThrowable);
82+
}
83+
84+
if ($resolved) {
85+
return $resolvedValue;
86+
}
87+
7888
while ($wait) {
7989
Loop::run();
8090
}
8191

8292
if ($rejected) {
83-
// promise is rejected with an unexpected value (Promise API v1 or v2 only)
84-
if (!$exception instanceof \Throwable) {
85-
$exception = new \UnexpectedValueException(
86-
'Promise rejected with unexpected value of type ' . (is_object($exception) ? get_class($exception) : gettype($exception))
87-
);
88-
}
89-
90-
throw $exception;
93+
awaitThrow($rejectedThrowable);
9194
}
9295

93-
return $resolved;
96+
return $resolvedValue;
9497
}
9598

99+
/**
100+
* @internal
101+
* @param \Exception|\Throwable $rejectedThrowable
102+
*/
103+
function awaitThrow($rejectedThrowable)
104+
{
105+
// promise is rejected with an unexpected value (Promise API v1 or v2 only)
106+
if (!$rejectedThrowable instanceof \Exception && !$rejectedThrowable instanceof \Throwable) {
107+
$rejectedThrowable = new \UnexpectedValueException(
108+
'Promise rejected with unexpected value of type ' . (is_object($rejectedThrowable) ? get_class($rejectedThrowable) : gettype($rejectedThrowable))
109+
);
110+
}
111+
112+
throw $rejectedThrowable;
113+
}
96114

97115
/**
98116
* Execute a Generator-based coroutine to "await" promises.

tests/AwaitTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ public function testAwaitShouldNotCreateAnyGarbageReferencesForRejectedPromise()
122122
$this->assertEquals(0, gc_collect_cycles());
123123
}
124124

125+
public function testAlreadyFulfilledPromiseShouldNotSuspendFiber()
126+
{
127+
for ($i = 0; $i < 6; $i++) {
128+
$this->assertSame($i, React\Async\await(React\Promise\resolve($i)));
129+
}
130+
}
131+
125132
public function testAwaitShouldNotCreateAnyGarbageReferencesForPromiseRejectedWithNullValue()
126133
{
127134
if (!interface_exists('React\Promise\CancellablePromiseInterface')) {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy