PromiseTimer

Build Status

ReactPHP 的基础上为Promise构建的一个简单的超时实现。

目录

用法

这个轻量级的库仅包含一些简单的功能。 所有功能都位于React\Promise\Timer命名空间下。

以下示例假定您使用与此类似的导入语句:

use React\Promise\Timer;

Timer\timeout(…);

或者,也可以用它们完整的命名空间来引用它们:

\React\Promise\Timer\timeout(…);

timeout()

timeout(PromiseInterface $promise, $time, LoopInterface $loop) 函数可以用来取消耗时太长的操作。 您需要传入一个$promise,表示一个挂起的操作和超时参数。 它返回一个新的Promise,具有以下兑现行为:

  • 如果传入的$promise$time秒之前被履行,则用其履行值兑现最终的promise
  • 如果传入的$promise$time秒之前被拒绝,则以其拒绝值产生拒绝的promise
  • 如果传入的$promise$time秒之前未兑现,则取消操作并产生 TimeoutException 拒绝的promise

设定的$time值将用于启动计时器,该计时器一旦触发将取消挂起的操作。 这意味着,如果传递的值很小(或为负),它仍将启动计时器,从而在将来的最早时间触发。

如果传入的$promise已经被兑现,那么产生的promise将立即履行或拒绝,而无需启动计时器。

仅处理解析值的常见用例如下所示:

$promise = accessSomeRemoteResource();
Timer\timeout($promise, 10.0, $loop)->then(function ($value) {
    // the operation finished within 10.0 seconds
});

一个完整的示例如下所示:

$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
        }
    }
);

或者,如果您使用的是react/promise v2.2.0 或更高版本,请执行以下操作:

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

如上所述,timeout() 函数花费的时间太长,则会取消底层操作。最终的承诺会被TimeoutException拒绝。

然而,底层传入$promise发生了什么比较棘手的事情: 定时器一旦触发后,我们将尝试调用$promise->cancel() 传入$promise依次调用它的取消处理程序

这意味着实际上是在传入$promise来处理取消支持

  • 常见的用例包括清理资源,如打开的网络套接字或文件句柄,或终止外部进程或计时器。
  • 如果传入的$promise不支持取消,这是不允许的。 这意味着,虽然最终的promise仍将被拒绝,但底层传入的$promise可能仍处于挂起状态,因此可能继续占用资源。

有关取消处理程序的详细信息,请参见下一章。

Cancellation handler

例如,上述操作的实现如下所示:

function accessSomeRemoteResource()
{
    return new Promise(
        function ($resolve, $reject) use (&$socket) {
            // 创建承诺,就会调用此方法
            // 常见的用例涉及打开资源并最终进行释放资源
            $socket = createSocket();
            $socket->on('data', function ($data) use ($resolve) {
                $resolve($data);
            });
        },
        function ($resolve, $reject) use (&$socket) {
            // 在此promise上调用'cancel()'后,该函数会被调用
            // 常见的用例包括清除资源然后拒绝
            $socket->close();
            $reject(new \RuntimeException('Operation cancelled'));
        }
    );
}

在此示例中,$promise->cancel()将调用已注册的取消处理程序,该处理程序随后关闭网络套接字并拒绝Promise实例。

如果没有向Promise构造函数传递取消处理程序,那么调用它的cancel()方法无效。可能是挂起状态,可以继续消耗资源。

有关承诺取消的更多细节,请参阅 Promise文档

Input cancellation

不管超时处理如何,您也可以在任何时候显式地cancel() $promise。 因此timeout()处理不会影响$promise的取消,如下例所示:

$promise = accessSomeRemoteResource();
$timeout = Timer\timeout($promise, 10.0, $loop);

$promise->cancel();

注册的cancellation handler 负责处理cancel()调用:

  • 如上所述,常见的应用涉及资源清理,然后拒绝 Promise。 如果传入的$promise被拒绝,那么超时将被中止,产生的promise也将被拒绝。

  • 如果传入的$promise仍然挂起,那么超时将继续运行,直到计时器到期。 如果传入$promise没有注册cancellation handler ,那么超时也继续运行,直到计时器到期。

Output cancellation

同样,你也可以像这样显式地cancel()生成如下承诺:

$promise = accessSomeRemoteResource();
$timeout = Timer\timeout($promise, 10.0, $loop);

$timeout->cancel();

请注意,这与上面的 input cancellation 示例非常相似。因此,它的行为也非常相似。 对结果promise调用cancel()只会尝试cancel()传入$promise。 这意味着我们不承担结果的责任,完全由传入$promise来支持取消处理。 注册的 cancellation handler 负责处理cancel()调用:

  • 如上所述,常见的用法涉及到资源清理,然后会拒绝这个$promise。 如果传入$promise被拒绝,那么超时将被中止,并且产生的承诺也将被拒绝。
  • 如果传入$promise仍然挂起,则超时将继续运行,直到计时器过期。 如果传入$promise没有注册 cancellation handler ,则超时也将继续运行,直到计时器过期。

要再次重申,请注意,对结果Promise调用cancel()仅会尝试取消传入$promise。 然后由传入$promise的取消处理程序来解决$promise。 如果在发生超时时传入$promise仍然兑现,则将触发常规的timeout cancellation 处理, 并通过 TimeoutException 有效地拒绝输出$promise

这样做是为了与 timeout cancellation 处理保持一致,并且还因为通常是这样使用的:

$timeout = Timer\timeout(accessSomeRemoteResource(), 10.0, $loop);

$timeout->cancel();

如上所述,该示例按预期工作,并清理了分配给传入$promise的所有资源。

请注意,如果传入$promise不支持取消,则此操作无效。 这意味着,虽然超时后仍然会拒绝产生的promise,但底层传入的$promise可能仍然是挂起的,因此可以继续消耗资源。

Collections

如果要等待多个promise兑现,则可以使用如下所示的常规promise函数:

$promises = array(
    accessSomeRemoteResource(),
    accessSomeRemoteResource(),
    accessSomeRemoteResource()
);

$promise = \React\Promise\all($promises);

Timer\timeout($promise, 10, $loop)->then(function ($values) {
    // *所有*的诺言得以实现
});

适用于所有promise集合的函数,即all(),race(),any(),some()等。

有关Promise函数的更多详细信息,请参考Promise文档

resolve()

可以使用resolve($time, LoopInterface $loop)函数来创建一个新的Promise,它以$time为履行值,在$time秒内解析。

Timer\resolve(1.5, $loop)->then(function ($time) {
    echo 'Thanks for waiting ' . $time . ' seconds' . PHP_EOL;
});

在内部,设定的$time值将用于启动一个计时器,一旦触发,就会兑现承诺。 这意味着,如果您传递一个非常小(或负值)的值,它仍然会启动一个计时器,因此将在未来尽可能早的时间触发。

Resolve cancellation

您可以在任何时候显式cancel()生成的计时器承诺:

$timer = Timer\resolve(2.0, $loop);

$timer->cancel();

这将中止计时器并通过RuntimeException拒绝

reject()

函数reject($time, LoopInterface $loop)可以用来创建一个新的承诺,该承诺在$time秒内通过TimeoutException拒绝。

Timer\reject(2.0, $loop)->then(null, function (TimeoutException $e) {
    echo 'Rejected after ' . $e->getTimeout() . ' seconds ' . PHP_EOL;
});

设定的$time值将用于启动计时器,该计时器一旦触发将拒绝承诺。 这意味着,如果传递的值很小(或为负),它仍将启动计时器,从而在将来的最早时间触发。

此函数是对 resolve() 函数的补充,可以用作更高级别的Promise开发者的基本构建块。

Reject cancellation

你可以在任何时候显式地cancel()产生的计时器承诺:

$timer = Timer\reject(2.0, $loop);

$timer->cancel();

这将中止计时器并通过RuntimeException来“拒绝”。

TimeoutException

TimeoutException扩展了PHP内置的RuntimeException

getTimeout()方法可用于获取以秒为单位的超时值。

安装

推荐的安装这个库的方法是通过ComposerComposer 新手?

该项目遵循SemVer , 默认安装最新支持的版本:

$ composer require react/promise-timer:^1.6

有关版本升级的详细信息,请参见CHANGELOG

该项目旨在在任何平台上运行,因此不需要任何PHP扩展,并支持通过 PHP 7+HHVM在旧版PHP 5.3上运行。

强烈推荐在这个项目中使用PHP 7+

测试

要运行测试套件,首先需要克隆这个存储库,然后安装所有依赖项通过Composer:

$ composer install

要运行测试套件,请转到项目根目录并运行:

$ php vendor/bin/phpunit

License

MIT, see LICENSE file.

results matching ""

    No results matching ""

    results matching ""

      No results matching ""