mirror of
https://github.com/danog/amp.git
synced 2024-12-02 09:27:46 +01:00
Rename Deferred to DeferredFuture
This commit is contained in:
parent
112e813914
commit
99a6b487c3
@ -1,21 +1,18 @@
|
||||
---
|
||||
layout: docs
|
||||
title: Promises
|
||||
permalink: /promises/
|
||||
layout: docs title: Promises permalink: /promises/
|
||||
---
|
||||
A `Promise` is an object representing the eventual result of an asynchronous operation.
|
||||
There are three states:
|
||||
A `Promise` is an object representing the eventual result of an asynchronous operation. There are three states:
|
||||
|
||||
- **Success**: The promise resolved successfully.
|
||||
- **Failure**: The promise failed.
|
||||
- **Pending**: The promise has not been resolved yet.
|
||||
- **Success**: The promise resolved successfully.
|
||||
- **Failure**: The promise failed.
|
||||
- **Pending**: The promise has not been resolved yet.
|
||||
|
||||
A successful resolution is like returning a value in synchronous code while failing a promise is like throwing an exception.
|
||||
|
||||
Promises are the basic unit of concurrency in asynchronous applications.
|
||||
In Amp they implement the `Amp\Promise` interface.
|
||||
These objects should be thought of as placeholders for values or tasks that might not be complete immediately.
|
||||
A successful resolution is like returning a value in synchronous code while failing a promise is like throwing an
|
||||
exception.
|
||||
|
||||
Promises are the basic unit of concurrency in asynchronous applications. In Amp they implement the `Amp\Promise`
|
||||
interface. These objects should be thought of as placeholders for values or tasks that might not be complete
|
||||
immediately.
|
||||
|
||||
Another way to approach asynchronous APIs is using callbacks that are passed when the operation is started.
|
||||
|
||||
@ -31,11 +28,13 @@ doSomething(function ($error, $value) {
|
||||
|
||||
The callback approach has several drawbacks.
|
||||
|
||||
- Passing callbacks and doing further actions in them that depend on the result of the first action gets messy really quickly.
|
||||
- An explicit callback is required as input parameter to the function, and the return value is simply unused. There's no way to use this API without involving a callback.
|
||||
- Passing callbacks and doing further actions in them that depend on the result of the first action gets messy really
|
||||
quickly.
|
||||
- An explicit callback is required as input parameter to the function, and the return value is simply unused. There's no
|
||||
way to use this API without involving a callback.
|
||||
|
||||
That's where promises come into play.
|
||||
They're simple placeholders that are returned and allow a callback (or several callbacks) to be registered.
|
||||
That's where promises come into play. They're simple placeholders that are returned and allow a callback (or several
|
||||
callbacks) to be registered.
|
||||
|
||||
```php
|
||||
doSomething()->onResolve(function ($error, $value) {
|
||||
@ -47,17 +46,19 @@ doSomething()->onResolve(function ($error, $value) {
|
||||
});
|
||||
```
|
||||
|
||||
This doesn't seem a lot better at first sight, we have just moved the callback.
|
||||
But in fact this enabled a lot.
|
||||
We can now write helper functions like [`Amp\Promise\all()`](https://amphp.org/amp/promises/combinators#all) which subscribe to several of those placeholders and combine them. We don't have to write any complicated code to combine the results of several callbacks.
|
||||
This doesn't seem a lot better at first sight, we have just moved the callback. But in fact this enabled a lot. We can
|
||||
now write helper functions like [`Amp\Promise\all()`](https://amphp.org/amp/promises/combinators#all) which subscribe to
|
||||
several of those placeholders and combine them. We don't have to write any complicated code to combine the results of
|
||||
several callbacks.
|
||||
|
||||
But the most important improvement of promises is that they allow writing [coroutines](https://amphp.org/amp/coroutines/), which completely eliminate the need for _any_ callbacks.
|
||||
But the most important improvement of promises is that they allow
|
||||
writing [coroutines](https://amphp.org/amp/coroutines/), which completely eliminate the need for _any_ callbacks.
|
||||
|
||||
Coroutines make use of PHP's generators.
|
||||
Every time a promise is `yield`ed, the coroutine subscribes to the promise and automatically continues it once the promise resolved.
|
||||
On successful resolution the coroutine will send the resolution value into the generator using [`Generator::send()`](https://secure.php.net/generator.send).
|
||||
On failure it will throw the exception into the generator using [`Generator::throw()`](https://secure.php.net/generator.throw).
|
||||
This allows writing asynchronous code almost like synchronous code.
|
||||
Coroutines make use of PHP's generators. Every time a promise is `yield`ed, the coroutine subscribes to the promise and
|
||||
automatically continues it once the promise resolved. On successful resolution the coroutine will send the resolution
|
||||
value into the generator using [`Generator::send()`](https://secure.php.net/generator.send). On failure it will throw
|
||||
the exception into the generator using [`Generator::throw()`](https://secure.php.net/generator.throw). This allows
|
||||
writing asynchronous code almost like synchronous code.
|
||||
|
||||
{:.note}
|
||||
> Amp's `Promise` interface **does not** conform to the "Thenables" abstraction common in JavaScript promise implementations. Chaining `.then()` calls is a suboptimal method for avoiding callback hell in a world with generator coroutines. Instead, Amp utilizes PHP generators as described above.
|
||||
@ -72,13 +73,16 @@ interface Promise {
|
||||
}
|
||||
```
|
||||
|
||||
In its simplest form the `Amp\Promise` aggregates callbacks for dealing with results once they eventually resolve. While most code will not interact with this API directly thanks to [coroutines](../coroutines/), let's take a quick look at the one simple API method exposed on `Amp\Promise` implementations:
|
||||
In its simplest form the `Amp\Promise` aggregates callbacks for dealing with results once they eventually resolve. While
|
||||
most code will not interact with this API directly thanks to [coroutines](../coroutines/), let's take a quick look at
|
||||
the one simple API method exposed on `Amp\Promise` implementations:
|
||||
|
||||
| Parameter | Callback Signature |
|
||||
| ------------ | ------------------------------------------ |
|
||||
| `$onResolve` | `function ($error = null, $result = null)` |
|
||||
|
||||
`Amp\Promise::onResolve()` accepts an error-first callback. This callback is responsible for reacting to the eventual result represented by the promise placeholder. For example:
|
||||
`Amp\Promise::onResolve()` accepts an error-first callback. This callback is responsible for reacting to the eventual
|
||||
result represented by the promise placeholder. For example:
|
||||
|
||||
```php
|
||||
<?php
|
||||
@ -99,22 +103,32 @@ $promise->onResolve(function (Throwable $error = null, $result = null) {
|
||||
});
|
||||
```
|
||||
|
||||
Those familiar with JavaScript code generally reflect that the above interface quickly devolves into ["callback hell"](http://callbackhell.com/), and they're correct. We will shortly see how to avoid this problem in the [coroutines](../coroutines/README.md) section.
|
||||
Those familiar with JavaScript code generally reflect that the above interface quickly devolves
|
||||
into ["callback hell"](http://callbackhell.com/), and they're correct. We will shortly see how to avoid this problem in
|
||||
the [coroutines](../coroutines/README.md) section.
|
||||
|
||||
## Promise Creation
|
||||
|
||||
Promises can be created in several different ways. Most code will use [`Amp\call()`](https://amphp.org/amp/coroutines/helpers#call) which takes a function and runs it as coroutine if it returns a `Generator`.
|
||||
Promises can be created in several different ways. Most code will
|
||||
use [`Amp\call()`](https://amphp.org/amp/coroutines/helpers#call) which takes a function and runs it as coroutine if it
|
||||
returns a `Generator`.
|
||||
|
||||
### Success and Failure
|
||||
|
||||
Sometimes values are immediately available. This might be due to them being cached, but can also be the case if an interface mandates a promise to be returned to allow for async I/O but the specific implementation always having the result directly available. In these cases `Amp\Success` and `Amp\Failure` can be used to construct an immediately resolved promise. `Amp\Success` accepts a resolution value. `Amp\Failure` accepts an exception as failure reason.
|
||||
Sometimes values are immediately available. This might be due to them being cached, but can also be the case if an
|
||||
interface mandates a promise to be returned to allow for async I/O but the specific implementation always having the
|
||||
result directly available. In these cases `Amp\Success` and `Amp\Failure` can be used to construct an immediately
|
||||
resolved promise. `Amp\Success` accepts a resolution value. `Amp\Failure` accepts an exception as failure reason.
|
||||
|
||||
### Deferred
|
||||
|
||||
{:.note}
|
||||
> The `Deferred` API described below is an advanced API that many applications probably don't need. Use [`Amp\call()`](https://amphp.org/amp/coroutines/helpers#call) or [promise combinators](https://amphp.org/amp/promises/combinators) instead where possible.
|
||||
|
||||
`Amp\Deferred` is the abstraction responsible for resolving future values once they become available. A library that resolves values asynchronously creates an `Amp\Deferred` and uses it to return an `Amp\Promise` to API consumers. Once the async library determines that the value is ready it resolves the promise held by the API consumer using methods on the linked promisor.
|
||||
`Amp\Deferred` is the abstraction responsible for resolving future values once they become available. A library that
|
||||
resolves values asynchronously creates an `Amp\Deferred` and uses it to return an `Amp\Promise` to API consumers. Once
|
||||
the async library determines that the value is ready it resolves the promise held by the API consumer using methods on
|
||||
the linked promisor.
|
||||
|
||||
```php
|
||||
final class Deferred
|
||||
@ -127,17 +141,22 @@ final class Deferred
|
||||
|
||||
#### `promise()`
|
||||
|
||||
Returns the corresponding `Promise` instance. `Deferred` and `Promise` are separated, so the consumer of the promise can't fulfill it. You should always return `$deferred->promise()` to API consumers. If you're passing `Deferred` objects around, you're probably doing something wrong.
|
||||
Returns the corresponding `Promise` instance. `Deferred` and `Promise` are separated, so the consumer of the promise
|
||||
can't fulfill it. You should always return `$deferred->promise()` to API consumers. If you're passing `Deferred` objects
|
||||
around, you're probably doing something wrong.
|
||||
|
||||
#### `resolve()`
|
||||
|
||||
Resolves the promise with the first parameter as value, otherwise `null`. If a `Amp\Promise` is passed, the resolution will wait until the passed promise has been resolved. Invokes all registered `Promise::onResolve()` callbacks.
|
||||
Resolves the promise with the first parameter as value, otherwise `null`. If a `Amp\Promise` is passed, the resolution
|
||||
will wait until the passed promise has been resolved. Invokes all registered `Promise::onResolve()` callbacks.
|
||||
|
||||
#### `fail()`
|
||||
|
||||
Makes the promise fail. Invokes all registered `Promise::onResolve()` callbacks with the passed `Throwable` as `$error` argument.
|
||||
Makes the promise fail. Invokes all registered `Promise::onResolve()` callbacks with the passed `Throwable` as `$error`
|
||||
argument.
|
||||
|
||||
Here's a simple example of an async value producer `asyncMultiply()` creating a deferred and returning the associated promise to its API consumer.
|
||||
Here's a simple example of an async value producer `asyncMultiply()` creating a deferred and returning the associated
|
||||
promise to its API consumer.
|
||||
|
||||
```php
|
||||
<?php // Example async producer using promisor
|
||||
@ -147,7 +166,7 @@ use Amp\Loop;
|
||||
function asyncMultiply($x, $y)
|
||||
{
|
||||
// Create a new promisor
|
||||
$deferred = new Amp\Deferred;
|
||||
$deferred = new Amp\DeferredFuture;
|
||||
|
||||
// Resolve the async result one second from now
|
||||
Loop::delay($msDelay = 1000, function () use ($deferred, $x, $y) {
|
||||
|
@ -5,7 +5,7 @@ namespace Amp;
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
final class Deferred
|
||||
final class DeferredFuture
|
||||
{
|
||||
/** @var Internal\FutureState<T> */
|
||||
private Internal\FutureState $state;
|
@ -91,7 +91,7 @@ final class Future
|
||||
/**
|
||||
* @param FutureState<T> $state
|
||||
*
|
||||
* @internal Use {@see Deferred} or {@see async()} to create and resolve a Future.
|
||||
* @internal Use {@see DeferredFuture} or {@see async()} to create and resolve a Future.
|
||||
*/
|
||||
public function __construct(FutureState $state)
|
||||
{
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Amp\Future;
|
||||
|
||||
use Amp\CancelledException;
|
||||
use Amp\Deferred;
|
||||
use Amp\DeferredFuture;
|
||||
use Amp\Future;
|
||||
use Amp\TimeoutCancellation;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@ -23,7 +23,7 @@ class AllTest extends TestCase
|
||||
|
||||
public function testTwoFirstPending(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
|
||||
EventLoop::delay(0.01, fn () => $deferred->complete(1));
|
||||
|
||||
@ -32,7 +32,7 @@ class AllTest extends TestCase
|
||||
|
||||
public function testArrayDestructuring(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
|
||||
EventLoop::delay(0.01, fn () => $deferred->complete(1));
|
||||
|
||||
@ -55,7 +55,7 @@ class AllTest extends TestCase
|
||||
$this->expectException(\Exception::class);
|
||||
$this->expectExceptionMessage('foo');
|
||||
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
EventLoop::delay(0.1, static fn () => $deferred->error(new \Exception('bar')));
|
||||
|
||||
all([Future::error(new \Exception('foo')), $deferred->getFuture()]);
|
||||
@ -76,13 +76,13 @@ class AllTest extends TestCase
|
||||
{
|
||||
$this->expectException(CancelledException::class);
|
||||
$deferreds = \array_map(function (int $value) {
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
EventLoop::delay($value / 10, fn () => $deferred->complete($value));
|
||||
return $deferred;
|
||||
}, \range(1, 3));
|
||||
|
||||
all(\array_map(
|
||||
fn (Deferred $deferred) => $deferred->getFuture(),
|
||||
fn (DeferredFuture $deferred) => $deferred->getFuture(),
|
||||
$deferreds
|
||||
), new TimeoutCancellation(0.2));
|
||||
}
|
||||
@ -90,13 +90,13 @@ class AllTest extends TestCase
|
||||
public function testCompleteBeforeCancellation(): void
|
||||
{
|
||||
$deferreds = \array_map(function (int $value) {
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
EventLoop::delay($value / 10, fn () => $deferred->complete($value));
|
||||
return $deferred;
|
||||
}, \range(1, 3));
|
||||
|
||||
self::assertSame([1, 2, 3], all(\array_map(
|
||||
fn (Deferred $deferred) => $deferred->getFuture(),
|
||||
fn (DeferredFuture $deferred) => $deferred->getFuture(),
|
||||
$deferreds
|
||||
), new TimeoutCancellation(0.5)));
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ namespace Amp\Future;
|
||||
|
||||
use Amp\CancelledException;
|
||||
use Amp\CompositeException;
|
||||
use Amp\Deferred;
|
||||
use Amp\DeferredFuture;
|
||||
use Amp\Future;
|
||||
use Amp\TimeoutCancellation;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@ -24,7 +24,7 @@ class AnyTest extends TestCase
|
||||
|
||||
public function testTwoFirstPending(): void
|
||||
{
|
||||
$deferred = new Deferred();
|
||||
$deferred = new DeferredFuture();
|
||||
|
||||
self::assertSame(2, any([$deferred->getFuture(), Future::complete(2)]));
|
||||
}
|
||||
@ -54,13 +54,13 @@ class AnyTest extends TestCase
|
||||
{
|
||||
$this->expectException(CancelledException::class);
|
||||
$deferreds = \array_map(function (int $value) {
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
EventLoop::delay($value / 10, fn () => $deferred->complete($value));
|
||||
return $deferred;
|
||||
}, \range(1, 3));
|
||||
|
||||
any(\array_map(
|
||||
fn (Deferred $deferred) => $deferred->getFuture(),
|
||||
fn (DeferredFuture $deferred) => $deferred->getFuture(),
|
||||
$deferreds
|
||||
), new TimeoutCancellation(0.05));
|
||||
}
|
||||
@ -68,18 +68,18 @@ class AnyTest extends TestCase
|
||||
public function testCompleteBeforeCancellation(): void
|
||||
{
|
||||
$deferreds = \array_map(function (int $value) {
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
EventLoop::delay($value / 10, fn () => $deferred->complete($value));
|
||||
return $deferred;
|
||||
}, \range(1, 3));
|
||||
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
$deferred->error(new \Exception('foo'));
|
||||
|
||||
\array_unshift($deferreds, $deferred);
|
||||
|
||||
self::assertSame(1, any(\array_map(
|
||||
fn (Deferred $deferred) => $deferred->getFuture(),
|
||||
fn (DeferredFuture $deferred) => $deferred->getFuture(),
|
||||
$deferreds
|
||||
), new TimeoutCancellation(0.2)));
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
namespace Amp\Future;
|
||||
|
||||
use Amp\CancelledException;
|
||||
use Amp\Deferred;
|
||||
use Amp\DeferredCancellation;
|
||||
use Amp\DeferredFuture;
|
||||
use Amp\Future;
|
||||
use Amp\PHPUnit\AsyncTestCase;
|
||||
use Amp\PHPUnit\LoopCaughtException;
|
||||
@ -37,11 +37,11 @@ class FutureTest extends AsyncTestCase
|
||||
* @var \Generator<int, Future<string>, void, void>
|
||||
*/
|
||||
$iterator = (function () {
|
||||
yield (new Deferred)->getFuture();
|
||||
yield (new DeferredFuture)->getFuture();
|
||||
yield $this->delay(0.1, 'a');
|
||||
|
||||
// Never joins
|
||||
(new Deferred)->getFuture()->await();
|
||||
(new DeferredFuture)->getFuture()->await();
|
||||
})();
|
||||
|
||||
foreach (Future::iterate($iterator) as $index => $future) {
|
||||
@ -52,7 +52,7 @@ class FutureTest extends AsyncTestCase
|
||||
|
||||
public function testComplete(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
$future = $deferred->getFuture();
|
||||
|
||||
$deferred->complete('result');
|
||||
@ -62,7 +62,7 @@ class FutureTest extends AsyncTestCase
|
||||
|
||||
public function testCompleteAsync(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
$future = $deferred->getFuture();
|
||||
|
||||
EventLoop::delay(0.01, fn () => $deferred->complete('result'));
|
||||
@ -79,7 +79,7 @@ class FutureTest extends AsyncTestCase
|
||||
|
||||
public function testError(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
$future = $deferred->getFuture();
|
||||
|
||||
$deferred->error(new \Exception('foo'));
|
||||
@ -92,7 +92,7 @@ class FutureTest extends AsyncTestCase
|
||||
|
||||
public function testErrorAsync(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
$future = $deferred->getFuture();
|
||||
|
||||
EventLoop::delay(0.01, fn () => $deferred->error(new \Exception('foo')));
|
||||
@ -115,7 +115,7 @@ class FutureTest extends AsyncTestCase
|
||||
|
||||
public function testCompleteWithFuture(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
|
||||
$this->expectException(\Error::class);
|
||||
$this->expectExceptionMessage('Cannot complete with an instance of');
|
||||
@ -145,7 +145,7 @@ class FutureTest extends AsyncTestCase
|
||||
|
||||
public function testCompleteThenCancelJoin(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
$source = new DeferredCancellation;
|
||||
$future = $deferred->getFuture();
|
||||
|
||||
@ -159,7 +159,7 @@ class FutureTest extends AsyncTestCase
|
||||
|
||||
public function testUnhandledError(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
$deferred->error(new TestException);
|
||||
unset($deferred);
|
||||
|
||||
@ -176,7 +176,7 @@ class FutureTest extends AsyncTestCase
|
||||
|
||||
public function testIgnoringUnhandledErrors(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
$deferred->getFuture()->ignore();
|
||||
$deferred->error(new TestException);
|
||||
unset($deferred);
|
||||
@ -209,7 +209,7 @@ class FutureTest extends AsyncTestCase
|
||||
|
||||
public function testMapWithPendingFuture(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
|
||||
$future = $deferred->getFuture();
|
||||
$future = $future->map(static fn (int $value) => $value + 1);
|
||||
@ -252,7 +252,7 @@ class FutureTest extends AsyncTestCase
|
||||
|
||||
public function testCatchWithPendingFuture(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
|
||||
$future = $deferred->getFuture();
|
||||
$future = $future->catch(static fn (\Throwable $exception) => 1);
|
||||
@ -296,7 +296,7 @@ class FutureTest extends AsyncTestCase
|
||||
|
||||
public function testFinallyWithPendingFuture(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
|
||||
$future = $deferred->getFuture();
|
||||
$future = $future->finally($this->createCallback(1));
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Amp\Future;
|
||||
|
||||
use Amp\CancelledException;
|
||||
use Amp\Deferred;
|
||||
use Amp\DeferredFuture;
|
||||
use Amp\Future;
|
||||
use Amp\TimeoutCancellation;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@ -23,7 +23,7 @@ class RaceTest extends TestCase
|
||||
|
||||
public function testTwoFirstPending(): void
|
||||
{
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
|
||||
self::assertSame(2, Future\race([$deferred->getFuture(), Future::complete(2)]));
|
||||
}
|
||||
@ -52,13 +52,13 @@ class RaceTest extends TestCase
|
||||
$this->expectException(CancelledException::class);
|
||||
|
||||
$deferreds = \array_map(function (int $value) {
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
EventLoop::delay($value / 10, fn () => $deferred->complete($value));
|
||||
return $deferred;
|
||||
}, \range(1, 3));
|
||||
|
||||
race(\array_map(
|
||||
fn (Deferred $deferred) => $deferred->getFuture(),
|
||||
fn (DeferredFuture $deferred) => $deferred->getFuture(),
|
||||
$deferreds
|
||||
), new TimeoutCancellation(0.05));
|
||||
}
|
||||
@ -66,13 +66,13 @@ class RaceTest extends TestCase
|
||||
public function testCompleteBeforeCancellation(): void
|
||||
{
|
||||
$deferreds = \array_map(function (int $value) {
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
EventLoop::delay($value / 10, fn () => $deferred->complete($value));
|
||||
return $deferred;
|
||||
}, \range(1, 3));
|
||||
|
||||
self::assertSame(1, race(\array_map(
|
||||
fn (Deferred $deferred) => $deferred->getFuture(),
|
||||
fn (DeferredFuture $deferred) => $deferred->getFuture(),
|
||||
$deferreds
|
||||
), new TimeoutCancellation(0.2)));
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace Amp\Future;
|
||||
|
||||
use Amp\CancelledException;
|
||||
use Amp\Deferred;
|
||||
use Amp\DeferredFuture;
|
||||
use Amp\Future;
|
||||
use Amp\TimeoutCancellation;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@ -50,13 +50,13 @@ class SettleTest extends TestCase
|
||||
{
|
||||
$this->expectException(CancelledException::class);
|
||||
$deferreds = \array_map(function (int $value) {
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
EventLoop::delay($value / 10, fn () => $deferred->complete($value));
|
||||
return $deferred;
|
||||
}, \range(1, 3));
|
||||
|
||||
settle(\array_map(
|
||||
fn (Deferred $deferred) => $deferred->getFuture(),
|
||||
fn (DeferredFuture $deferred) => $deferred->getFuture(),
|
||||
$deferreds
|
||||
), new TimeoutCancellation(0.05));
|
||||
}
|
||||
@ -64,13 +64,13 @@ class SettleTest extends TestCase
|
||||
public function testCompleteBeforeCancellation(): void
|
||||
{
|
||||
$deferreds = \array_map(function (int $value) {
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
EventLoop::delay($value / 10, fn () => $deferred->complete($value));
|
||||
return $deferred;
|
||||
}, \range(1, 3));
|
||||
|
||||
self::assertSame([[], \range(1, 3)], settle(\array_map(
|
||||
fn (Deferred $deferred) => $deferred->getFuture(),
|
||||
fn (DeferredFuture $deferred) => $deferred->getFuture(),
|
||||
$deferreds
|
||||
), new TimeoutCancellation(0.5)));
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ namespace Amp\Future;
|
||||
|
||||
use Amp\CancelledException;
|
||||
use Amp\CompositeException;
|
||||
use Amp\Deferred;
|
||||
use Amp\DeferredFuture;
|
||||
use Amp\Future;
|
||||
use Amp\TimeoutCancellation;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@ -24,7 +24,7 @@ class SomeTest extends TestCase
|
||||
|
||||
public function testTwoFirstPending(): void
|
||||
{
|
||||
$deferred = new Deferred();
|
||||
$deferred = new DeferredFuture();
|
||||
|
||||
self::assertSame([1 => 2], some([$deferred->getFuture(), Future::complete(2)], 1));
|
||||
}
|
||||
@ -55,13 +55,13 @@ class SomeTest extends TestCase
|
||||
{
|
||||
$this->expectException(CancelledException::class);
|
||||
$deferreds = \array_map(function (int $value) {
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
EventLoop::delay($value / 10, fn () => $deferred->complete($value));
|
||||
return $deferred;
|
||||
}, \range(1, 3));
|
||||
|
||||
some(\array_map(
|
||||
fn (Deferred $deferred) => $deferred->getFuture(),
|
||||
fn (DeferredFuture $deferred) => $deferred->getFuture(),
|
||||
$deferreds
|
||||
), 3, new TimeoutCancellation(0.05));
|
||||
}
|
||||
@ -69,13 +69,13 @@ class SomeTest extends TestCase
|
||||
public function testCompleteBeforeCancellation(): void
|
||||
{
|
||||
$deferreds = \array_map(function (int $value) {
|
||||
$deferred = new Deferred;
|
||||
$deferred = new DeferredFuture;
|
||||
EventLoop::delay($value / 10, fn () => $deferred->complete($value));
|
||||
return $deferred;
|
||||
}, \range(1, 3));
|
||||
|
||||
self::assertSame(\range(1, 3), some(\array_map(
|
||||
fn (Deferred $deferred) => $deferred->getFuture(),
|
||||
fn (DeferredFuture $deferred) => $deferred->getFuture(),
|
||||
$deferreds
|
||||
), 3, new TimeoutCancellation(0.5)));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user