Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 65 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,119 +88,134 @@ $loop = React\EventLoop\Factory::create();

### sleep()

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

```php
Block\sleep(1.5, $loop);
```

The $time value will be used as a timer for the loop so that it keeps running
until the timeout 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 will only return after the given `$time` has elapsed. In the
meantime, the event loop will run any other events attached to the same loop
until the timer fires. If there are no other events attached to this loop,
it will behave similar to the built-in [`sleep()`](https://www.php.net/manual/en/function.sleep.php).

While this may look similar to PHP's [`sleep()`](https://www.php.net/sleep) function,
it's actual way more powerful:
Instead of making the whole process sleep and handing over control to your operating system,
this function actually executes the loop in the meantime.
This is particularly useful if you've attached more async tasks to the same loop instance.
If there are no other (async) tasks, this will behave similar to `sleep()`.
Internally, the `$time` argument will be used as a timer for the loop so that
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.

### await()

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

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

Once the promise is resolved, this will return whatever the promise resolves to.
This function will only return after the given `$promise` has settled, i.e.
either fulfilled or rejected. In the meantime, the event loop will run any
events attached to the same loop until the promise settles.

Once the promise is fulfilled, this function will return whatever the promise
resolved to.

Once the promise is rejected, this will throw whatever the promise rejected with.
If the promise did not reject with an `Exception`, then this function will
throw an `UnexpectedValueException` instead.
Once the promise is rejected, this will throw whatever the promise rejected
with. If the promise did not reject with an `Exception`, then this function
will throw an `UnexpectedValueException` instead.

```php
try {
$value = Block\await($promise, $loop);
$result = Block\await($promise, $loop);
// promise successfully fulfilled with $value
echo 'Result: ' . $value;
echo 'Result: ' . $result;
} catch (Exception $exception) {
// promise rejected with $exception
echo 'ERROR: ' . $exception->getMessage();
}
```

If no $timeout is given and the promise stays pending, then this will
potentially wait/block forever until the promise is settled.
If no `$timeout` argument is given and the promise stays pending, then this
will potentially wait/block forever until the promise is settled.

If a $timeout is given and the promise is still pending once the timeout
triggers, this will `cancel()` the promise and throw a `TimeoutException`.
If a `$timeout` argument is given and the promise is still pending once the
timeout triggers, this will `cancel()` the promise and throw a `TimeoutException`.
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.

### awaitAny()

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

```php
$promises = array(
$promise1,
$promise2
);

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

echo 'First result: ' . $firstResult;
```

Once the first promise is resolved, this will try to `cancel()` all
remaining promises and return whatever the first promise resolves to.
This function will only return after ANY of the given `$promises` has been
fulfilled or will throw when ALL of them have been rejected. In the meantime,
the event loop will run any events attached to the same loop.

If ALL promises fail to resolve, this will fail and throw an `Exception`.
Once ANY promise is fulfilled, this function will return whatever this
promise resolved to and will try to `cancel()` all remaining promises.

If no $timeout is given and either promise stays pending, then this will
potentially wait/block forever until the first promise is settled.
Once ALL promises reject, this function will fail and throw an `UnderflowException`.
Likewise, this will throw if an empty array of `$promises` is passed.

If a $timeout is given and either promise is still pending once the timeout
triggers, this will `cancel()` all pending promises and throw a `TimeoutException`.
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.
If no `$timeout` argument is given and ALL promises stay pending, then this
will potentially wait/block forever until the promise is fulfilled.

If a `$timeout` argument is given and ANY promises are still pending once
the timeout triggers, this will `cancel()` all pending promises and throw a
`TimeoutException`. 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.

### awaitAll()

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

```php
$promises = array(
$promise1,
$promise2
);

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

echo 'First promise resolved with: ' . $allResults[0];
```

Once the last promise resolves, this will return an array with whatever
This function will only return after ALL of the given `$promises` have been
fulfilled or will throw when ANY of them have been rejected. In the meantime,
the event loop will run any events attached to the same loop.

Once ALL promises are fulfilled, this will return an array with whatever
each promise resolves to. Array keys will be left intact, i.e. they can
be used to correlate the return array to the promises passed.
Likewise, this will return an empty array if an empty array of `$promises` is passed.

If ANY promise fails to resolve, 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.
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.

If no $timeout is given and either promise stays pending, then this will
potentially wait/block forever until the last promise is settled.
If no `$timeout` argument is given and ANY promises stay pending, then this
will potentially wait/block forever until the promise is fulfilled.

If a $timeout is given and either promise is still pending once the timeout
triggers, this will `cancel()` all pending promises and throw a `TimeoutException`.
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.
If a `$timeout` argument is given and ANY promises are still pending once
the timeout triggers, this will `cancel()` all pending promises and throw a
`TimeoutException`. 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.

## Install

Expand Down
135 changes: 99 additions & 36 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,65 @@
use React\Promise\Timer\TimeoutException;

/**
* wait/sleep for $time seconds
* Wait/sleep for `$time` seconds.
*
* The $time value will be used as a timer for the loop so that it keeps running
* until the timeout 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.
* ```php
* Block\sleep(1.5, $loop);
* ```
*
* This function will only return after the given `$time` has elapsed. In the
* meantime, the event loop will run any other events attached to the same loop
* until the timer fires. If there are no other events attached to this loop,
* it will behave similar to the built-in [`sleep()`](https://www.php.net/manual/en/function.sleep.php).
*
* Internally, the `$time` argument will be used as a timer for the loop so that
* 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.
*
* @param float $time
* @param LoopInterface $loop
* @return void
*/
function sleep($time, LoopInterface $loop)
{
await(Timer\resolve($time, $loop), $loop);
}

/**
* block waiting for the given $promise to resolve
* Block waiting for the given `$promise` to be fulfilled.
*
* ```php
* $result = Block\await($promise, $loop, $timeout);
* ```
*
* Once the promise is resolved, this will return whatever the promise resolves to.
* This function will only return after the given `$promise` has settled, i.e.
* either fulfilled or rejected. In the meantime, the event loop will run any
* events attached to the same loop until the promise settles.
*
* Once the promise is rejected, this will throw whatever the promise rejected with.
* If the promise did not reject with an `Exception`, then this function will
* throw an `UnexpectedValueException` instead.
* Once the promise is fulfilled, this function will return whatever the promise
* resolved to.
*
* If no $timeout is given and the promise stays pending, then this will
* potentially wait/block forever until the promise is settled.
* Once the promise is rejected, this will throw whatever the promise rejected
* with. If the promise did not reject with an `Exception`, then this function
* will throw an `UnexpectedValueException` instead.
*
* If a $timeout is given and the promise is still pending once the timeout
* triggers, this will cancel() the promise and throw a `TimeoutException`.
* ```php
* try {
* $result = Block\await($promise, $loop);
* // promise successfully fulfilled with $value
* echo 'Result: ' . $result;
* } catch (Exception $exception) {
* // promise rejected with $exception
* echo 'ERROR: ' . $exception->getMessage();
* }
* ```
*
* If no `$timeout` argument is given and the promise stays pending, then this
* will potentially wait/block forever until the promise is settled.
*
* If a `$timeout` argument is given and the promise is still pending once the
* timeout triggers, this will `cancel()` the promise and throw a `TimeoutException`.
* 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.
*
Expand Down Expand Up @@ -100,20 +130,37 @@ function ($error) use (&$exception, &$rejected, &$wait, $loop) {
}

/**
* wait for ANY of the given promises to resolve
* Wait for ANY of the given promises to be fulfilled.
*
* Once the first promise is resolved, this will try to cancel() all
* remaining promises and return whatever the first promise resolves to.
* ```php
* $promises = array(
* $promise1,
* $promise2
* );
*
* If ALL promises fail to resolve, this will fail and throw an Exception.
* $firstResult = Block\awaitAny($promises, $loop, $timeout);
*
* If no $timeout is given and either promise stays pending, then this will
* potentially wait/block forever until the first promise is settled.
* echo 'First result: ' . $firstResult;
* ```
*
* If a $timeout is given and either promise is still pending once the timeout
* triggers, this will cancel() all pending promises and throw a `TimeoutException`.
* 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 will only return after ANY of the given `$promises` has been
* fulfilled or will throw when ALL of them have been rejected. In the meantime,
* the event loop will run any events attached to the same loop.
*
* Once ANY promise is fulfilled, this function will return whatever this
* 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.
*
* If no `$timeout` argument is given and ALL promises stay pending, then this
* will potentially wait/block forever until the promise is fulfilled.
*
* If a `$timeout` argument is given and ANY promises are still pending once
* the timeout triggers, this will `cancel()` all pending promises and throw a
* `TimeoutException`. 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.
*
* @param array $promises
* @param LoopInterface $loop
Expand Down Expand Up @@ -161,24 +208,39 @@ function awaitAny(array $promises, LoopInterface $loop, $timeout = null)
}

/**
* wait for ALL of the given promises to resolve
* Wait for ALL of the given promises to be fulfilled.
*
* ```php
* $promises = array(
* $promise1,
* $promise2
* );
*
* $allResults = Block\awaitAll($promises, $loop, $timeout);
*
* Once the last promise resolves, this will return an array with whatever
* echo 'First promise resolved with: ' . $allResults[0];
* ```
*
* This function will only return after ALL of the given `$promises` have been
* fulfilled or will throw when ANY of them have been rejected. In the meantime,
* the event loop will run any events attached to the same loop.
*
* Once ALL promises are fulfilled, this will return an array with whatever
* each promise resolves to. Array keys will be left intact, i.e. they can
* be used to correlate the return array to the promises passed.
*
* If ANY promise fails to resolve, 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.
* 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.
*
* If no $timeout is given and either promise stays pending, then this will
* potentially wait/block forever until the last promise is settled.
* If no `$timeout` argument is given and ANY promises stay pending, then this
* will potentially wait/block forever until the promise is fulfilled.
*
* If a $timeout is given and either promise is still pending once the timeout
* triggers, this will cancel() all pending promises and throw a `TimeoutException`.
* 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.
* If a `$timeout` argument is given and ANY promises are still pending once
* the timeout triggers, this will `cancel()` all pending promises and throw a
* `TimeoutException`. 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.
*
* @param array $promises
* @param LoopInterface $loop
Expand Down Expand Up @@ -210,6 +272,7 @@ function awaitAll(array $promises, LoopInterface $loop, $timeout = null)
*
* @internal
* @param array $promises
* @return void
*/
function _cancelAllPromises(array $promises)
{
Expand Down