init
This commit is contained in:
372
vendor/react/promise-timer/README.md
vendored
Executable file
372
vendor/react/promise-timer/README.md
vendored
Executable file
@@ -0,0 +1,372 @@
|
||||
# PromiseTimer
|
||||
|
||||
[](https://travis-ci.org/reactphp/promise-timer)
|
||||
|
||||
A trivial implementation of timeouts for `Promise`s, built on top of [ReactPHP](https://reactphp.org/).
|
||||
|
||||
**Table of contents**
|
||||
|
||||
* [Usage](#usage)
|
||||
* [timeout()](#timeout)
|
||||
* [Timeout cancellation](#timeout-cancellation)
|
||||
* [Cancellation handler](#cancellation-handler)
|
||||
* [Input cancellation](#input-cancellation)
|
||||
* [Output cancellation](#output-cancellation)
|
||||
* [Collections](#collections)
|
||||
* [resolve()](#resolve)
|
||||
* [Resolve cancellation](#resolve-cancellation)
|
||||
* [reject()](#reject)
|
||||
* [Reject cancellation](#reject-cancellation)
|
||||
* [TimeoutException](#timeoutexception)
|
||||
* [Install](#install)
|
||||
* [Tests](#tests)
|
||||
* [License](#license)
|
||||
|
||||
## Usage
|
||||
|
||||
This lightweight library consists only of a few simple functions.
|
||||
All functions reside under the `React\Promise\Timer` namespace.
|
||||
|
||||
The below examples assume you use an import statement similar to this:
|
||||
|
||||
```php
|
||||
use React\Promise\Timer;
|
||||
|
||||
Timer\timeout(…);
|
||||
```
|
||||
|
||||
Alternatively, you can also refer to them with their fully-qualified name:
|
||||
|
||||
```php
|
||||
\React\Promise\Timer\timeout(…);
|
||||
```
|
||||
|
||||
### timeout()
|
||||
|
||||
The `timeout(PromiseInterface $promise, $time, LoopInterface $loop)` function
|
||||
can be used to *cancel* operations that take *too long*.
|
||||
You need to pass in an input `$promise` that represents a pending operation and timeout parameters.
|
||||
It returns a new `Promise` with the following resolution behavior:
|
||||
|
||||
* If the input `$promise` resolves before `$time` seconds, resolve the resulting promise with its fulfillment value.
|
||||
* If the input `$promise` rejects before `$time` seconds, reject the resulting promise with its rejection value.
|
||||
* If the input `$promise` does not settle before `$time` seconds, *cancel* the operation and reject the resulting promise with a [`TimeoutException`](#timeoutexception).
|
||||
|
||||
Internally, the given `$time` value will be used to start a timer that will
|
||||
*cancel* the pending operation once it 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.
|
||||
|
||||
If the input `$promise` is already settled, then the resulting promise will
|
||||
resolve or reject immediately without starting a timer at all.
|
||||
|
||||
A common use case for handling only resolved values looks like this:
|
||||
|
||||
```php
|
||||
$promise = accessSomeRemoteResource();
|
||||
Timer\timeout($promise, 10.0, $loop)->then(function ($value) {
|
||||
// the operation finished within 10.0 seconds
|
||||
});
|
||||
```
|
||||
|
||||
A more complete example could look like this:
|
||||
|
||||
```php
|
||||
$promise = accessSomeRemoteResource();
|
||||
Timer\timeout($promise, 10.0, $loop)->then(
|
||||
function ($value) {
|
||||
// the operation finished within 10.0 seconds
|
||||
},
|
||||
function ($error) {
|
||||
if ($error instanceof Timer\TimeoutException) {
|
||||
// the operation has failed due to a timeout
|
||||
} else {
|
||||
// the input operation has failed due to some other error
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Or if you're using [react/promise v2.2.0](https://github.com/reactphp/promise) or up:
|
||||
|
||||
```php
|
||||
Timer\timeout($promise, 10.0, $loop)
|
||||
->then(function ($value) {
|
||||
// the operation finished within 10.0 seconds
|
||||
})
|
||||
->otherwise(function (Timer\TimeoutException $error) {
|
||||
// the operation has failed due to a timeout
|
||||
})
|
||||
->otherwise(function ($error) {
|
||||
// the input operation has failed due to some other error
|
||||
})
|
||||
;
|
||||
```
|
||||
|
||||
#### Timeout cancellation
|
||||
|
||||
As discussed above, the [`timeout()`](#timeout) function will *cancel* the
|
||||
underlying operation if it takes *too long*.
|
||||
This means that you can be sure the resulting promise will then be rejected
|
||||
with a [`TimeoutException`](#timeoutexception).
|
||||
|
||||
However, what happens to the underlying input `$promise` is a bit more tricky:
|
||||
Once the timer fires, we will try to call
|
||||
[`$promise->cancel()`](https://github.com/reactphp/promise#cancellablepromiseinterfacecancel)
|
||||
on the input `$promise` which in turn invokes its [cancellation handler](#cancellation-handler).
|
||||
|
||||
This means that it's actually up the input `$promise` to handle
|
||||
[cancellation support](https://github.com/reactphp/promise#cancellablepromiseinterface).
|
||||
|
||||
* A common use case involves cleaning up any resources like open network sockets or
|
||||
file handles or terminating external processes or timers.
|
||||
|
||||
* If the given input `$promise` does not support cancellation, then this is a NO-OP.
|
||||
This means that while the resulting promise will still be rejected, the underlying
|
||||
input `$promise` may still be pending and can hence continue consuming resources.
|
||||
|
||||
See the following chapter for more details on the cancellation handler.
|
||||
|
||||
#### Cancellation handler
|
||||
|
||||
For example, an implementation for the above operation could look like this:
|
||||
|
||||
```php
|
||||
function accessSomeRemoteResource()
|
||||
{
|
||||
return new Promise(
|
||||
function ($resolve, $reject) use (&$socket) {
|
||||
// this will be called once the promise is created
|
||||
// a common use case involves opening any resources and eventually resolving
|
||||
$socket = createSocket();
|
||||
$socket->on('data', function ($data) use ($resolve) {
|
||||
$resolve($data);
|
||||
});
|
||||
},
|
||||
function ($resolve, $reject) use (&$socket) {
|
||||
// this will be called once calling `cancel()` on this promise
|
||||
// a common use case involves cleaning any resources and then rejecting
|
||||
$socket->close();
|
||||
$reject(new \RuntimeException('Operation cancelled'));
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
In this example, calling `$promise->cancel()` will invoke the registered cancellation
|
||||
handler which then closes the network socket and rejects the `Promise` instance.
|
||||
|
||||
If no cancellation handler is passed to the `Promise` constructor, then invoking
|
||||
its `cancel()` method it is effectively a NO-OP.
|
||||
This means that it may still be pending and can hence continue consuming resources.
|
||||
|
||||
For more details on the promise cancellation, please refer to the
|
||||
[Promise documentation](https://github.com/reactphp/promise#cancellablepromiseinterface).
|
||||
|
||||
#### Input cancellation
|
||||
|
||||
Irrespective of the timeout handling, you can also explicitly `cancel()` the
|
||||
input `$promise` at any time.
|
||||
This means that the `timeout()` handling does not affect cancellation of the
|
||||
input `$promise`, as demonstrated in the following example:
|
||||
|
||||
```php
|
||||
$promise = accessSomeRemoteResource();
|
||||
$timeout = Timer\timeout($promise, 10.0, $loop);
|
||||
|
||||
$promise->cancel();
|
||||
```
|
||||
|
||||
The registered [cancellation handler](#cancellation-handler) is responsible for
|
||||
handling the `cancel()` call:
|
||||
|
||||
* A described above, a common use involves resource cleanup and will then *reject*
|
||||
the `Promise`.
|
||||
If the input `$promise` is being rejected, then the timeout will be aborted
|
||||
and the resulting promise will also be rejected.
|
||||
* If the input `$promise` is still pending, then the timout will continue
|
||||
running until the timer expires.
|
||||
The same happens if the input `$promise` does not register a
|
||||
[cancellation handler](#cancellation-handler).
|
||||
|
||||
#### Output cancellation
|
||||
|
||||
Similarily, you can also explicitly `cancel()` the resulting promise like this:
|
||||
|
||||
```php
|
||||
$promise = accessSomeRemoteResource();
|
||||
$timeout = Timer\timeout($promise, 10.0, $loop);
|
||||
|
||||
$timeout->cancel();
|
||||
```
|
||||
|
||||
Note how this looks very similar to the above [input cancellation](#input-cancellation)
|
||||
example. Accordingly, it also behaves very similar.
|
||||
|
||||
Calling `cancel()` on the resulting promise will merely try
|
||||
to `cancel()` the input `$promise`.
|
||||
This means that we do not take over responsibility of the outcome and it's
|
||||
entirely up to the input `$promise` to handle cancellation support.
|
||||
|
||||
The registered [cancellation handler](#cancellation-handler) is responsible for
|
||||
handling the `cancel()` call:
|
||||
|
||||
* As described above, a common use involves resource cleanup and will then *reject*
|
||||
the `Promise`.
|
||||
If the input `$promise` is being rejected, then the timeout will be aborted
|
||||
and the resulting promise will also be rejected.
|
||||
* If the input `$promise` is still pending, then the timout will continue
|
||||
running until the timer expires.
|
||||
The same happens if the input `$promise` does not register a
|
||||
[cancellation handler](#cancellation-handler).
|
||||
|
||||
To re-iterate, note that calling `cancel()` on the resulting promise will merely
|
||||
try to cancel the input `$promise` only.
|
||||
It is then up to the cancellation handler of the input promise to settle the promise.
|
||||
If the input promise is still pending when the timeout occurs, then the normal
|
||||
[timeout cancellation](#timeout-cancellation) handling will trigger, effectively rejecting
|
||||
the output promise with a [`TimeoutException`](#timeoutexception).
|
||||
|
||||
This is done for consistency with the [timeout cancellation](#timeout-cancellation)
|
||||
handling and also because it is assumed this is often used like this:
|
||||
|
||||
```php
|
||||
$timeout = Timer\timeout(accessSomeRemoteResource(), 10.0, $loop);
|
||||
|
||||
$timeout->cancel();
|
||||
```
|
||||
|
||||
As described above, this example works as expected and cleans up any resources
|
||||
allocated for the input `$promise`.
|
||||
|
||||
Note that if the given input `$promise` does not support cancellation, then this
|
||||
is a NO-OP.
|
||||
This means that while the resulting promise will still be rejected after the
|
||||
timeout, the underlying input `$promise` may still be pending and can hence
|
||||
continue consuming resources.
|
||||
|
||||
#### Collections
|
||||
|
||||
If you want to wait for multiple promises to resolve, you can use the normal promise primitives like this:
|
||||
|
||||
```php
|
||||
$promises = array(
|
||||
accessSomeRemoteResource(),
|
||||
accessSomeRemoteResource(),
|
||||
accessSomeRemoteResource()
|
||||
);
|
||||
|
||||
$promise = \React\Promise\all($promises);
|
||||
|
||||
Timer\timeout($promise, 10, $loop)->then(function ($values) {
|
||||
// *all* promises resolved
|
||||
});
|
||||
```
|
||||
|
||||
The applies to all promise collection primitives alike, i.e. `all()`, `race()`, `any()`, `some()` etc.
|
||||
|
||||
For more details on the promise primitives, please refer to the
|
||||
[Promise documentation](https://github.com/reactphp/promise#functions).
|
||||
|
||||
### resolve()
|
||||
|
||||
The `resolve($time, LoopInterface $loop)` function can be used to create a new Promise that
|
||||
resolves in `$time` seconds with the `$time` as the fulfillment value.
|
||||
|
||||
```php
|
||||
Timer\resolve(1.5, $loop)->then(function ($time) {
|
||||
echo 'Thanks for waiting ' . $time . ' seconds' . PHP_EOL;
|
||||
});
|
||||
```
|
||||
|
||||
Internally, the given `$time` value will be used to start a timer that will
|
||||
resolve the promise once it 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.
|
||||
|
||||
#### Resolve cancellation
|
||||
|
||||
You can explicitly `cancel()` the resulting timer promise at any time:
|
||||
|
||||
```php
|
||||
$timer = Timer\resolve(2.0, $loop);
|
||||
|
||||
$timer->cancel();
|
||||
```
|
||||
|
||||
This will abort the timer and *reject* with a `RuntimeException`.
|
||||
|
||||
### reject()
|
||||
|
||||
The `reject($time, LoopInterface $loop)` function can be used to create a new Promise
|
||||
which rejects in `$time` seconds with a `TimeoutException`.
|
||||
|
||||
```php
|
||||
Timer\reject(2.0, $loop)->then(null, function (TimeoutException $e) {
|
||||
echo 'Rejected after ' . $e->getTimeout() . ' seconds ' . PHP_EOL;
|
||||
});
|
||||
```
|
||||
|
||||
Internally, the given `$time` value will be used to start a timer that will
|
||||
reject the promise once it 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 complements the [`resolve()`](#resolve) function
|
||||
and can be used as a basic building block for higher-level promise consumers.
|
||||
|
||||
#### Reject cancellation
|
||||
|
||||
You can explicitly `cancel()` the resulting timer promise at any time:
|
||||
|
||||
```php
|
||||
$timer = Timer\reject(2.0, $loop);
|
||||
|
||||
$timer->cancel();
|
||||
```
|
||||
|
||||
This will abort the timer and *reject* with a `RuntimeException`.
|
||||
|
||||
### TimeoutException
|
||||
|
||||
The `TimeoutException` extends PHP's built-in `RuntimeException`.
|
||||
|
||||
The `getTimeout()` method can be used to get the timeout value in seconds.
|
||||
|
||||
## Install
|
||||
|
||||
The recommended way to install this library is [through Composer](https://getcomposer.org).
|
||||
[New to Composer?](https://getcomposer.org/doc/00-intro.md)
|
||||
|
||||
This project follows [SemVer](https://semver.org/).
|
||||
This will install the latest supported version:
|
||||
|
||||
```bash
|
||||
$ composer require react/promise-timer:^1.5
|
||||
```
|
||||
|
||||
See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
|
||||
|
||||
This project aims to run on any platform and thus does not require any PHP
|
||||
extensions and supports running on legacy PHP 5.3 through current PHP 7+ and
|
||||
HHVM.
|
||||
It's *highly recommended to use PHP 7+* for this project.
|
||||
|
||||
## Tests
|
||||
|
||||
To run the test suite, you first need to clone this repo and then install all
|
||||
dependencies [through Composer](https://getcomposer.org):
|
||||
|
||||
```bash
|
||||
$ composer install
|
||||
```
|
||||
|
||||
To run the test suite, go to the project root and run:
|
||||
|
||||
```bash
|
||||
$ php vendor/bin/phpunit
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT, see [LICENSE file](LICENSE).
|
||||
Reference in New Issue
Block a user