Skip to content

Commit

Permalink
Merge cfc6bca into c00edcc
Browse files Browse the repository at this point in the history
  • Loading branch information
joshdifabio committed Apr 29, 2016
2 parents c00edcc + cfc6bca commit f16fe82
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 8 deletions.
33 changes: 25 additions & 8 deletions src/Promise.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class Promise implements ExtendedPromiseInterface, CancellablePromiseInterface
private $requiredCancelRequests = 0;
private $cancelRequests = 0;

private $nextHandlerId = '0';

public function __construct(callable $resolver, callable $canceller = null)
{
$this->canceller = $canceller;
Expand All @@ -25,13 +27,26 @@ public function then(callable $onFulfilled = null, callable $onRejected = null,
return $this->result()->then($onFulfilled, $onRejected, $onProgress);
}

$handlerId = $this->nextHandlerId;
$cleanUpFn = function () use ($handlerId) {
if (isset($this->handlers[$handlerId])) {
unset($this->handlers[$handlerId]);
}
if (isset($this->progressHandlers[$handlerId])) {
unset($this->progressHandlers[$handlerId]);
}
};
$this->nextHandlerId++;

if (null === $this->canceller) {
return new static($this->resolver($onFulfilled, $onRejected, $onProgress));
return new static($this->resolver($handlerId, $onFulfilled, $onRejected, $onProgress), $cleanUpFn);
}

$this->requiredCancelRequests++;

return new static($this->resolver($onFulfilled, $onRejected, $onProgress), function () {
return new static($this->resolver($handlerId, $onFulfilled, $onRejected, $onProgress), function () use ($cleanUpFn) {
$cleanUpFn();

if (++$this->cancelRequests < $this->requiredCancelRequests) {
return;
}
Expand All @@ -46,14 +61,16 @@ public function done(callable $onFulfilled = null, callable $onRejected = null,
return $this->result()->done($onFulfilled, $onRejected, $onProgress);
}

$this->handlers[] = function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected) {
$this->handlers[$this->nextHandlerId] = function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected) {
$promise
->done($onFulfilled, $onRejected);
};

if ($onProgress) {
$this->progressHandlers[] = $onProgress;
$this->progressHandlers[$this->nextHandlerId] = $onProgress;
}

$this->nextHandlerId++;
}

public function otherwise(callable $onRejected)
Expand Down Expand Up @@ -97,9 +114,9 @@ public function cancel()
$this->call($canceller);
}

private function resolver(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
private function resolver($handlerId, callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null)
{
return function ($resolve, $reject, $notify) use ($onFulfilled, $onRejected, $onProgress) {
return function ($resolve, $reject, $notify) use ($handlerId, $onFulfilled, $onRejected, $onProgress) {
if ($onProgress) {
$progressHandler = function ($update) use ($notify, $onProgress) {
try {
Expand All @@ -114,13 +131,13 @@ private function resolver(callable $onFulfilled = null, callable $onRejected = n
$progressHandler = $notify;
}

$this->handlers[] = function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject, $progressHandler) {
$this->handlers[$handlerId] = function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject, $progressHandler) {
$promise
->then($onFulfilled, $onRejected)
->done($resolve, $reject, $progressHandler);
};

$this->progressHandlers[] = $progressHandler;
$this->progressHandlers[$handlerId] = $progressHandler;
};
}

Expand Down
20 changes: 20 additions & 0 deletions tests/CancellationMemLeakTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
namespace React\Promise;

class CancellationMemLeakTest extends TestCase
{
public function testCancelCleansUp()
{
$mainDeferred = new Deferred;

$memoryUsage = memory_get_usage();

for ($i = 0; $i < 100000; $i++) {
$innerDeferred = new Deferred;
race([$mainDeferred->promise()->then(), $innerDeferred->promise()]);
$innerDeferred->resolve();
}

$this->assertLessThan(2 * $memoryUsage, memory_get_usage());
}
}

0 comments on commit f16fe82

Please sign in to comment.