@@ -9,7 +9,7 @@ final class Promise implements PromiseInterface
99
1010 private $ handlers = [];
1111
12- private $ remainingCancelRequests = 0 ;
12+ private $ requiredCancelRequests = 0 ;
1313
1414 public function __construct (callable $ resolver , callable $ canceller = null )
1515 {
@@ -27,14 +27,14 @@ public function then(callable $onFulfilled = null, callable $onRejected = null)
2727 return new static ($ this ->resolver ($ onFulfilled , $ onRejected ));
2828 }
2929
30- $ this ->remainingCancelRequests ++;
30+ $ this ->requiredCancelRequests ++;
3131
3232 return new static ($ this ->resolver ($ onFulfilled , $ onRejected ), function () {
33- if (--$ this ->remainingCancelRequests > 0 ) {
34- return ;
35- }
33+ $ this ->requiredCancelRequests --;
3634
37- $ this ->cancel ();
35+ if ($ this ->requiredCancelRequests <= 0 ) {
36+ $ this ->cancel ();
37+ }
3838 });
3939 }
4040
@@ -76,14 +76,37 @@ public function always(callable $onFulfilledOrRejected)
7676
7777 public function cancel ()
7878 {
79- if (null === $ this ->canceller ) {
80- return ;
81- }
82-
8379 $ canceller = $ this ->canceller ;
8480 $ this ->canceller = null ;
8581
86- $ this ->call ($ canceller );
82+ $ parentCanceller = null ;
83+
84+ if (null !== $ this ->result ) {
85+ // Go up the promise chain and reach the top most promise which is
86+ // itself not following another promise
87+ $ root = $ this ->unwrap ($ this ->result );
88+
89+ // Return if the root promise is already resolved or a
90+ // FulfilledPromise or RejectedPromise
91+ if (!$ root instanceof self || null !== $ root ->result ) {
92+ return ;
93+ }
94+
95+ $ root ->requiredCancelRequests --;
96+
97+ if ($ root ->requiredCancelRequests <= 0 ) {
98+ $ parentCanceller = [$ root , 'cancel ' ];
99+ }
100+ }
101+
102+ if (null !== $ canceller ) {
103+ $ this ->call ($ canceller );
104+ }
105+
106+ // For BC, we call the parent canceller after our own canceller
107+ if ($ parentCanceller ) {
108+ $ parentCanceller ();
109+ }
87110 }
88111
89112 private function resolver (callable $ onFulfilled = null , callable $ onRejected = null )
@@ -119,10 +142,22 @@ private function settle(PromiseInterface $result)
119142 {
120143 $ result = $ this ->unwrap ($ result );
121144
145+ if ($ result === $ this ) {
146+ $ result = new RejectedPromise (
147+ new \LogicException ('Cannot resolve a promise with itself. ' )
148+ );
149+ }
150+
151+ if ($ result instanceof self) {
152+ $ result ->requiredCancelRequests ++;
153+ } else {
154+ // Unset canceller only when not following a pending promise
155+ $ this ->canceller = null ;
156+ }
157+
122158 $ handlers = $ this ->handlers ;
123159
124160 $ this ->handlers = [];
125- $ this ->canceller = null ;
126161 $ this ->result = $ result ;
127162
128163 foreach ($ handlers as $ handler ) {
@@ -132,25 +167,8 @@ private function settle(PromiseInterface $result)
132167
133168 private function unwrap ($ promise )
134169 {
135- $ promise = $ this ->extract ($ promise );
136-
137170 while ($ promise instanceof self && null !== $ promise ->result ) {
138- $ promise = $ this ->extract ($ promise ->result );
139- }
140-
141- return $ promise ;
142- }
143-
144- private function extract ($ promise )
145- {
146- if ($ promise instanceof LazyPromise) {
147- $ promise = $ promise ->promise ();
148- }
149-
150- if ($ promise === $ this ) {
151- return new RejectedPromise (
152- new \LogicException ('Cannot resolve a promise with itself. ' )
153- );
171+ $ promise = $ promise ->result ;
154172 }
155173
156174 return $ promise ;
0 commit comments