|
2 | 2 |
|
3 | 3 | namespace React\Promise; |
4 | 4 |
|
5 | | -class Deferred implements PromiseInterface, ResolverInterface, PromisorInterface |
| 5 | +class Deferred implements PromiseInterface, ResolverInterface, PromisorInterface, CancellablePromiseInterface |
6 | 6 | { |
7 | 7 | private $completed; |
8 | 8 | private $promise; |
9 | 9 | private $resolver; |
10 | 10 | private $handlers = array(); |
11 | 11 | private $progressHandlers = array(); |
| 12 | + private $canceller; |
| 13 | + |
| 14 | + private $requiredCancelRequests = 0; |
| 15 | + private $cancelRequests = 0; |
| 16 | + |
| 17 | + public function __construct($canceller = null) |
| 18 | + { |
| 19 | + $this->canceller = $canceller; |
| 20 | + } |
12 | 21 |
|
13 | 22 | public function then($fulfilledHandler = null, $errorHandler = null, $progressHandler = null) |
14 | 23 | { |
15 | 24 | if (null !== $this->completed) { |
16 | 25 | return $this->completed->then($fulfilledHandler, $errorHandler, $progressHandler); |
17 | 26 | } |
18 | 27 |
|
19 | | - $deferred = new static(); |
| 28 | + $canceller = null; |
| 29 | + if ($this->canceller !== null) { |
| 30 | + $this->requiredCancelRequests++; |
| 31 | + |
| 32 | + $that = $this; |
| 33 | + $current =& $this->cancelRequests; |
| 34 | + $required =& $this->requiredCancelRequests; |
| 35 | + |
| 36 | + $canceller = function () use ($that, &$current, &$required) { |
| 37 | + if (++$current < $required) { |
| 38 | + return; |
| 39 | + } |
| 40 | + |
| 41 | + $that->cancel(); |
| 42 | + }; |
| 43 | + } |
| 44 | + |
| 45 | + $deferred = new static($canceller); |
20 | 46 |
|
21 | 47 | if (is_callable($progressHandler)) { |
22 | 48 | $progHandler = function ($update) use ($deferred, $progressHandler) { |
@@ -96,6 +122,32 @@ public function resolver() |
96 | 122 | return $this->resolver; |
97 | 123 | } |
98 | 124 |
|
| 125 | + public function cancel() |
| 126 | + { |
| 127 | + if (null === $this->canceller || null !== $this->completed) { |
| 128 | + return; |
| 129 | + } |
| 130 | + |
| 131 | + try { |
| 132 | + $that = $this; |
| 133 | + |
| 134 | + call_user_func( |
| 135 | + $this->canceller, |
| 136 | + function ($value = null) use ($that) { |
| 137 | + $that->resolve($value); |
| 138 | + }, |
| 139 | + function ($reason = null) use ($that) { |
| 140 | + $that->reject($reason); |
| 141 | + }, |
| 142 | + function ($update = null) use ($that) { |
| 143 | + $that->progress($update); |
| 144 | + } |
| 145 | + ); |
| 146 | + } catch (\Exception $e) { |
| 147 | + $this->reject($e); |
| 148 | + } |
| 149 | + } |
| 150 | + |
99 | 151 | protected function processQueue($queue, $value) |
100 | 152 | { |
101 | 153 | foreach ($queue as $handler) { |
|
0 commit comments