Skip to content

Commit

Permalink
Simplify usage by supporting new default loop
Browse files Browse the repository at this point in the history
  • Loading branch information
clue committed Oct 18, 2021
1 parent 5906e8d commit 514ec9c
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 61 deletions.
63 changes: 37 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,17 @@ non-blocking HTTP requests and block until the first (faster) one resolves.
```php
function blockingExample()
{
// use a unique event loop instance for all parallel operations
$loop = React\EventLoop\Factory::create();

// this example uses an HTTP client
// this could be pretty much everything that binds to an event loop
$browser = new React\Http\Browser($loop);
$browser = new React\Http\Browser();

// set up two parallel requests
$request1 = $browser->get('http://www.google.com/');
$request2 = $browser->get('http://www.google.co.uk/');

// keep the loop running (i.e. block) until the first response arrives
$fasterResponse = Clue\React\Block\awaitAny(array($request1, $request2), $loop);
$fasterResponse = Clue\React\Block\awaitAny(array($request1, $request2));

return $fasterResponse->getBody();
}
```
Expand Down Expand Up @@ -98,19 +95,9 @@ use Clue\React\Block;
Block\await(…);
```

### EventLoop

Each function is responsible for orchestrating the
[`EventLoop`](https://github.com/reactphp/event-loop#usage)
in order to make it run (block) until your conditions are fulfilled.

```php
$loop = React\EventLoop\Factory::create();
```

### sleep()

The `sleep($seconds, LoopInterface $loop): void` function can be used to
The `sleep(float $seconds, ?LoopInterface $loop = null): void` function can be used to
wait/sleep for `$time` seconds.

```php
Expand All @@ -127,13 +114,19 @@ it keeps running until this timer triggers. This implies that if you pass a
really small (or negative) value, it will still start a timer and will thus
trigger at the earliest possible time in the future.

This function takes an optional `LoopInterface|null $loop` parameter that can be used to
pass the event loop instance to use. You can use a `null` value here in order to
use the [default loop](https://github.com/reactphp/event-loop#loop). This value
SHOULD NOT be given unless you're sure you want to explicitly use a given event
loop instance.

### await()

The `await(PromiseInterface $promise, LoopInterface $loop, ?float $timeout = null): mixed` function can be used to
The `await(PromiseInterface $promise, ?LoopInterface $loop = null, ?float $timeout = null): mixed` function can be used to
block waiting for the given `$promise` to be fulfilled.

```php
$result = Clue\React\Block\await($promise, $loop);
$result = Clue\React\Block\await($promise);
```

This function will only return after the given `$promise` has settled, i.e.
Expand All @@ -149,7 +142,7 @@ will throw an `UnexpectedValueException` instead.

```php
try {
$result = Clue\React\Block\await($promise, $loop);
$result = Clue\React\Block\await($promise);
// promise successfully fulfilled with $result
echo 'Result: ' . $result;
} catch (Exception $exception) {
Expand All @@ -160,6 +153,12 @@ try {

See also the [examples](examples/).

This function takes an optional `LoopInterface|null $loop` parameter that can be used to
pass the event loop instance to use. You can use a `null` value here in order to
use the [default loop](https://github.com/reactphp/event-loop#loop). This value
SHOULD NOT be given unless you're sure you want to explicitly use a given event
loop instance.

If no `$timeout` argument is given and the promise stays pending, then this
will potentially wait/block forever until the promise is settled. To avoid
this, API authors creating promises are expected to provide means to
Expand All @@ -173,7 +172,7 @@ start a timer and will thus trigger at the earliest possible time in the future.

### awaitAny()

The `awaitAny(PromiseInterface[] $promises, LoopInterface $loop, ?float $timeout = null): mixed` function can be used to
The `awaitAny(PromiseInterface[] $promises, ?LoopInterface $loop = null, ?float $timeout = null): mixed` function can be used to
wait for ANY of the given promises to be fulfilled.

```php
Expand All @@ -182,7 +181,7 @@ $promises = array(
$promise2
);

$firstResult = Clue\React\Block\awaitAny($promises, $loop);
$firstResult = Clue\React\Block\awaitAny($promises);

echo 'First result: ' . $firstResult;
```
Expand All @@ -199,6 +198,12 @@ promise resolved to and will try to `cancel()` all remaining promises.
Once ALL promises reject, this function will fail and throw an `UnderflowException`.
Likewise, this will throw if an empty array of `$promises` is passed.

This function takes an optional `LoopInterface|null $loop` parameter that can be used to
pass the event loop instance to use. You can use a `null` value here in order to
use the [default loop](https://github.com/reactphp/event-loop#loop). This value
SHOULD NOT be given unless you're sure you want to explicitly use a given event
loop instance.

If no `$timeout` argument is given and ALL promises stay pending, then this
will potentially wait/block forever until the promise is fulfilled. To avoid
this, API authors creating promises are expected to provide means to
Expand All @@ -213,7 +218,7 @@ possible time in the future.

### awaitAll()

The `awaitAll(PromiseInterface[] $promises, LoopInterface $loop, ?float $timeout = null): mixed[]` function can be used to
The `awaitAll(PromiseInterface[] $promises, ?LoopInterface $loop = null, ?float $timeout = null): mixed[]` function can be used to
wait for ALL of the given promises to be fulfilled.

```php
Expand All @@ -222,7 +227,7 @@ $promises = array(
$promise2
);

$allResults = Clue\React\Block\awaitAll($promises, $loop);
$allResults = Clue\React\Block\awaitAll($promises);

echo 'First promise resolved with: ' . $allResults[0];
```
Expand All @@ -242,6 +247,12 @@ Once ANY promise rejects, this will try to `cancel()` all remaining promises
and throw an `Exception`. If the promise did not reject with an `Exception`,
then this function will throw an `UnexpectedValueException` instead.

This function takes an optional `LoopInterface|null $loop` parameter that can be used to
pass the event loop instance to use. You can use a `null` value here in order to
use the [default loop](https://github.com/reactphp/event-loop#loop). This value
SHOULD NOT be given unless you're sure you want to explicitly use a given event
loop instance.

If no `$timeout` argument is given and ANY promises stay pending, then this
will potentially wait/block forever until the promise is fulfilled. To avoid
this, API authors creating promises are expected to provide means to
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
},
"require": {
"php": ">=5.3",
"react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5",
"react/event-loop": "^1.2",
"react/promise": "^2.7 || ^1.2.1",
"react/promise-timer": "^1.5"
},
"require-dev": {
"phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
"react/http": "^1.0"
"react/http": "^1.4"
}
}
7 changes: 2 additions & 5 deletions examples/01-await.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,15 @@
*/
function requestHttp($url)
{
// use a unique event loop instance for this operation
$loop = React\EventLoop\Factory::create();

// This example uses an HTTP client
$browser = new React\Http\Browser($loop);
$browser = new React\Http\Browser();

// set up one request
$promise = $browser->get($url);

try {
// keep the loop running (i.e. block) until the response arrives
$result = Clue\React\Block\await($promise, $loop);
$result = Clue\React\Block\await($promise);

// promise successfully fulfilled with $result
return $result;
Expand Down
7 changes: 2 additions & 5 deletions examples/02-await-any.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@
*/
function requestHttpFastestOfMultiple($url1, $url2)
{
// use a unique event loop instance for all parallel operations
$loop = React\EventLoop\Factory::create();

// This example uses an HTTP client
$browser = new React\Http\Browser($loop);
$browser = new React\Http\Browser();

// set up two parallel requests
$promises = array(
Expand All @@ -24,7 +21,7 @@ function requestHttpFastestOfMultiple($url1, $url2)

try {
// keep the loop running (i.e. block) until the first response arrives
$fasterResponse = Clue\React\Block\awaitAny($promises, $loop);
$fasterResponse = Clue\React\Block\awaitAny($promises);

// promise successfully fulfilled with $fasterResponse
return $fasterResponse;
Expand Down
7 changes: 2 additions & 5 deletions examples/03-await-all.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@
*/
function requestHttpMultiple($url1, $url2)
{
// use a unique event loop instance for all parallel operations
$loop = React\EventLoop\Factory::create();

// This example uses an HTTP client
$browser = new React\Http\Browser($loop);
$browser = new React\Http\Browser();

// set up two parallel requests
$promises = array(
Expand All @@ -24,7 +21,7 @@ function requestHttpMultiple($url1, $url2)

try {
// keep the loop running (i.e. block) until all responses arrive
$allResults = Clue\React\Block\awaitAll($promises, $loop);
$allResults = Clue\React\Block\awaitAll($promises);

// promise successfully fulfilled with $allResults
return $allResults;
Expand Down
60 changes: 43 additions & 17 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

namespace Clue\React\Block;

use React\EventLoop\Loop;
use React\EventLoop\LoopInterface;
use React\Promise\PromiseInterface;
use React\Promise\CancellablePromiseInterface;
use UnderflowException;
use Exception;
use React\Promise;
use React\Promise\CancellablePromiseInterface;
use React\Promise\PromiseInterface;
use React\Promise\Timer;
use React\Promise\Timer\TimeoutException;
use Exception;
use UnderflowException;

/**
* Wait/sleep for `$time` seconds.
Expand All @@ -28,11 +29,17 @@
* really small (or negative) value, it will still start a timer and will thus
* trigger at the earliest possible time in the future.
*
* This function takes an optional `LoopInterface|null $loop` parameter that can be used to
* pass the event loop instance to use. You can use a `null` value here in order to
* use the [default loop](https://github.com/reactphp/event-loop#loop). This value
* SHOULD NOT be given unless you're sure you want to explicitly use a given event
* loop instance.
*
* @param float $time
* @param LoopInterface $loop
* @param ?LoopInterface $loop
* @return void
*/
function sleep($time, LoopInterface $loop)
function sleep($time, LoopInterface $loop = null)
{
await(Timer\resolve($time, $loop), $loop);
}
Expand Down Expand Up @@ -68,6 +75,12 @@ function sleep($time, LoopInterface $loop)
*
* See also the [examples](../examples/).
*
* This function takes an optional `LoopInterface|null $loop` parameter that can be used to
* pass the event loop instance to use. You can use a `null` value here in order to
* use the [default loop](https://github.com/reactphp/event-loop#loop). This value
* SHOULD NOT be given unless you're sure you want to explicitly use a given event
* loop instance.
*
* If no `$timeout` argument is given and the promise stays pending, then this
* will potentially wait/block forever until the promise is settled. To avoid
* this, API authors creating promises are expected to provide means to
Expand All @@ -80,18 +93,19 @@ function sleep($time, LoopInterface $loop)
* start a timer and will thus trigger at the earliest possible time in the future.
*
* @param PromiseInterface $promise
* @param LoopInterface $loop
* @param null|float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
* @param ?LoopInterface $loop
* @param ?float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
* @return mixed returns whatever the promise resolves to
* @throws Exception when the promise is rejected
* @throws TimeoutException if the $timeout is given and triggers
*/
function await(PromiseInterface $promise, LoopInterface $loop, $timeout = null)
function await(PromiseInterface $promise, LoopInterface $loop = null, $timeout = null)
{
$wait = true;
$resolved = null;
$exception = null;
$rejected = false;
$loop = $loop ?: Loop::get();

if ($timeout !== null) {
$promise = Timer\timeout($promise, $timeout, $loop);
Expand Down Expand Up @@ -164,6 +178,12 @@ function ($error) use (&$exception, &$rejected, &$wait, $loop) {
* Once ALL promises reject, this function will fail and throw an `UnderflowException`.
* Likewise, this will throw if an empty array of `$promises` is passed.
*
* This function takes an optional `LoopInterface|null $loop` parameter that can be used to
* pass the event loop instance to use. You can use a `null` value here in order to
* use the [default loop](https://github.com/reactphp/event-loop#loop). This value
* SHOULD NOT be given unless you're sure you want to explicitly use a given event
* loop instance.
*
* If no `$timeout` argument is given and ALL promises stay pending, then this
* will potentially wait/block forever until the promise is fulfilled. To avoid
* this, API authors creating promises are expected to provide means to
Expand All @@ -176,14 +196,14 @@ function ($error) use (&$exception, &$rejected, &$wait, $loop) {
* value, it will still start a timer and will thus trigger at the earliest
* possible time in the future.
*
* @param array $promises
* @param LoopInterface $loop
* @param null|float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
* @param array $promises
* @param ?LoopInterface $loop
* @param ?float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
* @return mixed returns whatever the first promise resolves to
* @throws Exception if ALL promises are rejected
* @throws TimeoutException if the $timeout is given and triggers
*/
function awaitAny(array $promises, LoopInterface $loop, $timeout = null)
function awaitAny(array $promises, LoopInterface $loop = null, $timeout = null)
{
// Explicitly overwrite argument with null value. This ensure that this
// argument does not show up in the stack trace in PHP 7+ only.
Expand Down Expand Up @@ -249,6 +269,12 @@ function awaitAny(array $promises, LoopInterface $loop, $timeout = null)
* and throw an `Exception`. If the promise did not reject with an `Exception`,
* then this function will throw an `UnexpectedValueException` instead.
*
* This function takes an optional `LoopInterface|null $loop` parameter that can be used to
* pass the event loop instance to use. You can use a `null` value here in order to
* use the [default loop](https://github.com/reactphp/event-loop#loop). This value
* SHOULD NOT be given unless you're sure you want to explicitly use a given event
* loop instance.
*
* If no `$timeout` argument is given and ANY promises stay pending, then this
* will potentially wait/block forever until the promise is fulfilled. To avoid
* this, API authors creating promises are expected to provide means to
Expand All @@ -261,14 +287,14 @@ function awaitAny(array $promises, LoopInterface $loop, $timeout = null)
* value, it will still start a timer and will thus trigger at the earliest
* possible time in the future.
*
* @param array $promises
* @param LoopInterface $loop
* @param null|float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
* @param array $promises
* @param ?LoopInterface $loop
* @param ?float $timeout [deprecated] (optional) maximum timeout in seconds or null=wait forever
* @return array returns an array with whatever each promise resolves to
* @throws Exception when ANY promise is rejected
* @throws TimeoutException if the $timeout is given and triggers
*/
function awaitAll(array $promises, LoopInterface $loop, $timeout = null)
function awaitAll(array $promises, LoopInterface $loop = null, $timeout = null)
{
// Explicitly overwrite argument with null value. This ensure that this
// argument does not show up in the stack trace in PHP 7+ only.
Expand Down
7 changes: 7 additions & 0 deletions tests/FunctionAwaitAllTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ public function testAwaitAllAllResolved()
$this->assertEquals(array('first' => 1, 'second' => 2), Block\awaitAll($all, $this->loop));
}

public function testAwaitAllReturnsArrayWithFulfilledValueFromSinglePromiseWithoutGivingLoop()
{
$promise = Promise\resolve(42);

$this->assertEquals(array(42), Block\awaitAll(array($promise)));
}

public function testAwaitAllRejected()
{
$all = array(
Expand Down
Loading

0 comments on commit 514ec9c

Please sign in to comment.