File tree 4 files changed +67
-11
lines changed
4 files changed +67
-11
lines changed Original file line number Diff line number Diff line change @@ -17,7 +17,7 @@ interface FiberInterface
17
17
{
18
18
public function resume (mixed $ value ): void ;
19
19
20
- public function throw (mixed $ throwable ): void ;
20
+ public function throw (\ Throwable $ throwable ): void ;
21
21
22
22
public function suspend (): mixed ;
23
23
}
Original file line number Diff line number Diff line change @@ -27,14 +27,8 @@ public function resume(mixed $value): void
27
27
Loop::futureTick (fn () => $ this ->fiber ->resume ($ value ));
28
28
}
29
29
30
- public function throw (mixed $ throwable ): void
30
+ public function throw (\ Throwable $ throwable ): void
31
31
{
32
- if (!$ throwable instanceof \Throwable) {
33
- $ throwable = new \UnexpectedValueException (
34
- 'Promise rejected with unexpected value of type ' . (is_object ($ throwable ) ? get_class ($ throwable ) : gettype ($ throwable ))
35
- );
36
- }
37
-
38
32
if ($ this ->fiber === null ) {
39
33
Loop::futureTick (static fn () => \Fiber::suspend (static fn () => throw $ throwable ));
40
34
return ;
Original file line number Diff line number Diff line change @@ -77,17 +77,49 @@ function async(callable $function): callable
77
77
*/
78
78
function await (PromiseInterface $ promise ): mixed
79
79
{
80
- $ fiber = FiberFactory::create ();
80
+ $ fiber = null ;
81
+ $ resolved = false ;
82
+ $ rejected = false ;
83
+ $ resolvedValue = null ;
84
+ $ rejectedThrowable = null ;
81
85
82
86
$ promise ->then (
83
- function (mixed $ value ) use (&$ resolved , $ fiber ): void {
87
+ function (mixed $ value ) use (&$ resolved , &$ resolvedValue , &$ fiber ): void {
88
+ if ($ fiber === null ) {
89
+ $ resolved = true ;
90
+ $ resolvedValue = $ value ;
91
+ return ;
92
+ }
93
+
84
94
$ fiber ->resume ($ value );
85
95
},
86
- function (mixed $ throwable ) use (&$ resolved , $ fiber ): void {
96
+ function (mixed $ throwable ) use (&$ rejected , &$ rejectedThrowable , &$ fiber ): void {
97
+ if (!$ throwable instanceof \Throwable) {
98
+ $ throwable = new \UnexpectedValueException (
99
+ 'Promise rejected with unexpected value of type ' . (is_object ($ throwable ) ? get_class ($ throwable ) : gettype ($ throwable ))
100
+ );
101
+ }
102
+
103
+ if ($ fiber === null ) {
104
+ $ rejected = true ;
105
+ $ rejectedThrowable = $ throwable ;
106
+ return ;
107
+ }
108
+
87
109
$ fiber ->throw ($ throwable );
88
110
}
89
111
);
90
112
113
+ if ($ resolved ) {
114
+ return $ resolvedValue ;
115
+ }
116
+
117
+ if ($ rejected ) {
118
+ throw $ rejectedThrowable ;
119
+ }
120
+
121
+ $ fiber = FiberFactory::create ();
122
+
91
123
return $ fiber ->suspend ();
92
124
}
93
125
Original file line number Diff line number Diff line change @@ -157,6 +157,36 @@ public function testAwaitShouldNotCreateAnyGarbageReferencesForPromiseRejectedWi
157
157
$ this ->assertEquals (0 , gc_collect_cycles ());
158
158
}
159
159
160
+ /**
161
+ * @dataProvider provideAwaiters
162
+ */
163
+ public function testAlreadyFulfilledPromiseShouldNotSuspendFiber (callable $ await )
164
+ {
165
+ for ($ i = 0 ; $ i < 6 ; $ i ++) {
166
+ $ this ->assertSame ($ i , $ await (React \Promise \resolve ($ i )));
167
+ }
168
+ }
169
+
170
+ /**
171
+ * @dataProvider provideAwaiters
172
+ */
173
+ public function testNestedAwaits (callable $ await )
174
+ {
175
+ $ this ->assertTrue ($ await (new Promise (function ($ resolve ) use ($ await ) {
176
+ $ resolve ($ await (new Promise (function ($ resolve ) use ($ await ) {
177
+ $ resolve ($ await (new Promise (function ($ resolve ) use ($ await ) {
178
+ $ resolve ($ await (new Promise (function ($ resolve ) use ($ await ) {
179
+ $ resolve ($ await (new Promise (function ($ resolve ) use ($ await ) {
180
+ Loop::addTimer (0.01 , function () use ($ resolve ) {
181
+ $ resolve (true );
182
+ });
183
+ })));
184
+ })));
185
+ })));
186
+ })));
187
+ })));
188
+ }
189
+
160
190
public function provideAwaiters (): iterable
161
191
{
162
192
yield 'await ' => [static fn (React \Promise \PromiseInterface $ promise ): mixed => React \Async \await ($ promise )];
You can’t perform that action at this time.
0 commit comments