Skip to content

Commit

Permalink
Added support for cancellable promises (#72, reactphp/promise#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
jmalloc committed Oct 5, 2014
1 parent 323534e commit 480a750
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 85 deletions.
7 changes: 2 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,8 @@ adapted into a [PromiseCoroutine](src/Coroutine/PromiseCoroutine.php) instance a
the promise has been fulfilled.

If the promise is resolved, the resulting value is returned from the yield statement. If it is rejected, the yield
statement throws an exception describing the error. **Recoil** does not yet support progress events.

React promises are based on the [Promise/A+](https://github.com/promises-aplus/promises-spec) specification, which does
not yet define a mechanism for cancellation of pending promises. As such, terminating a coroutine that is waiting on a
promise simply causes the promise resolution to be ignored.
statement throws an exception describing the error. If a strand is waiting on the resolution of a cancellable promise,
and execution of that strand is terminated the promise is cancelled. **Recoil** does not yet support progress events.

The [promise-dns example](examples/promise-dns) demonstrates using the [React DNS component](https://github.com/reactphp/dns),
a promised-based API, to resolve several domain names concurrently. [This example](examples/promise-dns-react) shows the
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"php": ">=5.5",
"evenement/evenement": "~2",
"icecave/repr": "~1",
"react/react": "0.4.0|~0.4.2"
"react/react": "0.4.0|~0.4.2",
"react/promise": "dev-cancellable-promise as 2.9.9"
},
"require-dev": {
"icecave/archer": "~1",
Expand Down
111 changes: 58 additions & 53 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 23 additions & 10 deletions src/Coroutine/PromiseCoroutine.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
namespace Recoil\Coroutine;

use Exception;
use React\Promise\CancellablePromiseInterface;
use React\Promise\PromiseInterface;
use Recoil\Coroutine\Exception\PromiseRejectedException;
use Recoil\Kernel\Strand\StrandInterface;
use React\Promise\PromiseInterface;

/**
* A coroutine that resumes when a promise is fulfilled or rejected.
Expand Down Expand Up @@ -47,19 +48,15 @@ function ($reason) use ($strand) {
}

/**
* Adapt a promise rejection reason into an exception.
* Inform the coroutine that the executing strand is being terminated.
*
* @param mixed $reason
*
* @return Exception
* @param StrandInterface $strand The strand that is executing the coroutine.
*/
protected function adaptReasonToException($reason)
public function terminate(StrandInterface $strand)
{
if ($reason instanceof Exception) {
return $reason;
if ($this->promise instanceof CancellablePromiseInterface) {
$this->promise->cancel();
}

return new PromiseRejectedException($reason);
}

/**
Expand All @@ -74,5 +71,21 @@ public function finalize(StrandInterface $strand)
$this->promise = null;
}

/**
* Adapt a promise rejection reason into an exception.
*
* @param mixed $reason
*
* @return Exception
*/
protected function adaptReasonToException($reason)
{
if ($reason instanceof Exception) {
return $reason;
}

return new PromiseRejectedException($reason);
}

private $promise;
}
Loading

0 comments on commit 480a750

Please sign in to comment.