Skip to content

Commit 5cbc26c

Browse files
committed
Merge remote-tracking branch 'origin/promise-rejection'
* origin/promise-rejection: Document passing promises to resolve()/reject() methods of a Defered/Resolver Ensure reject() always rejects with a reason value even if rejection value is a promise
2 parents edeeab3 + 0c0089e commit 5cbc26c

6 files changed

Lines changed: 128 additions & 5 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ Resolves a Deferred. All consumers are notified by having their
159159
`$fulfilledHandler` (which they registered via `$promise->then()`) called with
160160
`$result`.
161161

162+
If `$result` itself is a promise, the Deferred will transition to the state of
163+
this promise once it is resolved.
164+
162165
``` php
163166
$resolver->reject(mixed $reason = null);
164167
```
@@ -167,6 +170,9 @@ Rejects a Deferred, signalling that the Deferred's computation failed.
167170
All consumers are notified by having their `$errorHandler` (which they
168171
registered via `$promise->then()`) called with `$reason`.
169172

173+
If `$reason` itself is a promise, the Deferred will be rejected with the outcome
174+
of this promise regardless whether it fulfills or rejects.
175+
170176
``` php
171177
$resolver->progress(mixed $update = null);
172178
```

src/React/Promise/Deferred.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public function resolve($result = null)
6666

6767
public function reject($reason = null)
6868
{
69-
return $this->resolve(new RejectedPromise($reason));
69+
return $this->resolve(Util::rejectedPromiseFor($reason));
7070
}
7171

7272
public function progress($update = null)

src/React/Promise/Util.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,15 @@ public static function promiseFor($promiseOrValue)
1212

1313
return new FulfilledPromise($promiseOrValue);
1414
}
15+
16+
public static function rejectedPromiseFor($promiseOrValue)
17+
{
18+
if ($promiseOrValue instanceof PromiseInterface) {
19+
return $promiseOrValue->then(function ($value) {
20+
return new RejectedPromise($value);
21+
});
22+
}
23+
24+
return new RejectedPromise($promiseOrValue);
25+
}
1526
}

src/React/Promise/When.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ public static function resolve($promiseOrValue = null)
1111

1212
public static function reject($promiseOrValue = null)
1313
{
14-
return static::resolve($promiseOrValue)->then(function ($value = null) {
15-
return new RejectedPromise($value);
16-
});
14+
return Util::rejectedPromiseFor($promiseOrValue);
1715
}
1816

1917
public static function all($promisesOrValues, $fulfilledHandler = null, $errorHandler = null, $progressHandler = null)

tests/React/Promise/DeferredRejectTest.php

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
class DeferredRejectTest extends TestCase
1010
{
1111
/** @test */
12-
public function shouldReject()
12+
public function shouldRejectWithAnImmediateValue()
1313
{
1414
$d = new Deferred();
1515

@@ -28,6 +28,46 @@ public function shouldReject()
2828
->reject(1);
2929
}
3030

31+
/** @test */
32+
public function shouldRejectWithFulfilledPromise()
33+
{
34+
$d = new Deferred();
35+
36+
$mock = $this->createCallableMock();
37+
$mock
38+
->expects($this->once())
39+
->method('__invoke')
40+
->with($this->identicalTo(1));
41+
42+
$d
43+
->promise()
44+
->then($this->expectCallableNever(), $mock);
45+
46+
$d
47+
->resolver()
48+
->reject(new FulfilledPromise(1));
49+
}
50+
51+
/** @test */
52+
public function shouldRejectWithRejectedPromise()
53+
{
54+
$d = new Deferred();
55+
56+
$mock = $this->createCallableMock();
57+
$mock
58+
->expects($this->once())
59+
->method('__invoke')
60+
->with($this->identicalTo(1));
61+
62+
$d
63+
->promise()
64+
->then($this->expectCallableNever(), $mock);
65+
66+
$d
67+
->resolver()
68+
->reject(new RejectedPromise(1));
69+
}
70+
3171
/** @test */
3272
public function shouldReturnAPromiseForTheRejectionValue()
3373
{
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
namespace React\Promise;
4+
5+
/**
6+
* @group Util
7+
* @group UtilRejectedPromiseFor
8+
*/
9+
class UtilRejectedPromiseForTest extends TestCase
10+
{
11+
/** @test */
12+
public function shouldRejectWithAnImmediateValue()
13+
{
14+
$expected = 123;
15+
16+
$mock = $this->createCallableMock();
17+
$mock
18+
->expects($this->once())
19+
->method('__invoke')
20+
->with($this->identicalTo($expected));
21+
22+
Util::rejectedPromiseFor($expected)
23+
->then(
24+
$this->expectCallableNever(),
25+
$mock
26+
);
27+
}
28+
29+
/** @test */
30+
public function shouldRejectWithFulfilledPromise()
31+
{
32+
$expected = 123;
33+
34+
$resolved = new FulfilledPromise($expected);
35+
36+
$mock = $this->createCallableMock();
37+
$mock
38+
->expects($this->once())
39+
->method('__invoke')
40+
->with($this->identicalTo($expected));
41+
42+
Util::rejectedPromiseFor($resolved)
43+
->then(
44+
$this->expectCallableNever(),
45+
$mock
46+
);
47+
}
48+
49+
/** @test */
50+
public function shouldRejectWithRejectedPromise()
51+
{
52+
$expected = 123;
53+
54+
$resolved = new RejectedPromise($expected);
55+
56+
$mock = $this->createCallableMock();
57+
$mock
58+
->expects($this->once())
59+
->method('__invoke')
60+
->with($this->identicalTo($expected));
61+
62+
Util::rejectedPromiseFor($resolved)
63+
->then(
64+
$this->expectCallableNever(),
65+
$mock
66+
);
67+
}
68+
}

0 commit comments

Comments
 (0)