m3m0r7 / async-promise
一个用PHP编写的异步Promise库
0.0.1
2023-03-02 06:49 UTC
Requires
- php: >=8.1
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
- squizlabs/php_codesniffer: ^3.7
- swoole/ide-helper: ~5.0.0
README
英文 | 日语
AsyncPromise
什么是AsyncPromise?
AsyncPromise是一个PHP库,用于实现与JavaScript Promise相似的并发处理。
要求
- PHP 8.1或更高版本
- Swoole(如果您使用SwooleDriver)
如何安装
您可以使用以下命令进行安装
$ composer require m3m0r7/async-promise
如何使用
入门
Promise可以使用与JavaScript相同的方式进行使用,如下所示
<?php use AsyncPromise\Promise; (new Promise(function (callable $resolve) { $resolve('resolved!'); }))->then(function ($result) { // Show `resolved!` echo $result; });
您可以使用catch
方法接收异常。
<?php use AsyncPromise\Promise; (new Promise(function (callable $resolve) { throw new Exception('An error occurred'); }))->catch(function ($reason) { // Show `An error occurred` echo $reason; });
或者,您可以通过Promise回调函数的第二个参数来处理拒绝。
<?php use AsyncPromise\Promise; (new Promise(function (callable $_, callable $reject) { $reject('An error occurred'); }))->catch(function ($reason) { // Show `An error occurred` echo $reason; });
then
方法可以进行多重链式调用。
<?php use AsyncPromise\Promise; (new Promise(function (callable $resolve) { $resolve('resolved!'); }))->then(function ($result) { return 'nested chain: ' . $result; })->then(function ($result) { // Show `nested chain: resolved!` echo $result; });
在调用then
或catch
方法后,如果您想运行某些操作,可以使用finally
。
<?php use AsyncPromise\Promise; (new Promise(function (callable $resolve) { $resolve('resolved!'); }))->then(function ($result) { return 'nested chain: ' . $result; }, function ($reason) { echo $reason; })->finally(function ($result) { echo "Finally was reached"; });
Promise::all(array)
当所有传入的Promises
都得到满足时,返回一个新的Promise。
<?php use AsyncPromise\Promise; Promise::all([ 65535, 'text', (new Promise(fn (callable $resolve) => $resolve('fulfilled1'))), ['key' => 'value'], (new Promise(fn (callable $resolve) => $resolve('fulfilled2'))), ])->then(function (array $values) { // Show as following: // // Array // ( // [0] => 65535 // [1] => text // [2] => fulfilled1 // [3] => Array // ( // [key] => value // ) // // [4] => fulfilled2 // ) print_r($values); });
它将一直运行,直到拒绝,如下所示
<?php use AsyncPromise\Promise; Promise::all([ 65535, 'text', (new Promise(fn (callable $_, callable $reject) => $reject('rejected'))), ])->then(function (array $values) { // This statement is unreachable. print_r($values); })->catch(function (string $reason) { // Show `rejected` echo $reason; });
Promise::allSettled(array)
当所有传入的Promises
都被处理时,返回一个新的Promise。
<?php use AsyncPromise\Promise; Promise::allSettled([ 65535, 'text', (new Promise(fn (callable $resolve) => $resolve('resolved'))), (new Promise(fn (callable $_, callable $reject) => $reject('rejected'))), ])->then(function (array $values) { foreach ($values as $value) { if ($value->status === Promise::FULFILLED) { // Show as following: // fulfilled: 65535 // fulfilled: text // fulfilled: resolved echo "{$value->status}: {$value->value}\n"; } if ($value->status === Promise::REJECTED) { // Show as following: // rejected: rejected echo "{$value->status}: {$value->reason}\n"; } } });
Promise::race(array)
当传入的Promises
之一被处理时,返回一个新的Promise。
<?php use AsyncPromise\Promise; Promise::race([ (new Promise(fn (callable $resolve) => $resolve('resolved1'))), (new Promise(fn (callable $_, callable $reject) => $reject('rejected1'))), (new Promise(fn (callable $resolve) => $resolve('resolved2'))), (new Promise(fn (callable $_, callable $reject) => $reject('rejected2'))), ])->then(function ($value) { // Show `resolved1` echo "{$value}\n"; });
Promise::any(array)
当传入的Promises
之一被满足时,返回一个新的Promise。
<?php use AsyncPromise\Promise; Promise::any([ (new Promise(fn (callable $resolve) => $resolve('resolved1'))), (new Promise(fn (callable $_, callable $reject) => $reject('rejected1'))), (new Promise(fn (callable $resolve) => $resolve('resolved2'))), (new Promise(fn (callable $_, callable $reject) => $reject('rejected2'))), ])->then(function ($value) { // Show `resolved1` echo "{$value}\n"; });
如果没有满足,它将链接到catch
方法。
<?php use AsyncPromise\Promise; Promise::any([ (new Promise(fn (callable $_, callable $reject) => $reject('rejected1'))), (new Promise(fn (callable $_, callable $reject) => $reject('rejected2'))), (new Promise(fn (callable $_, callable $reject) => $reject('rejected3'))), (new Promise(fn (callable $_, callable $reject) => $reject('rejected4'))), ])->catch(function (array $values) { // Show as following: // // Array // ( // [0] => rejected1 // [1] => rejected2 // [2] => rejected3 // [3] => rejected4 // ) print_r($values); });
Promise::resolve(mixed)
将解决Promise。
<?php use AsyncPromise\Promise; Promise::resolve('resolved1') ->then(function (string $value) { // Show `resolved1` echo "resolved1\n"; });
将拒绝Promise。
<?php use AsyncPromise\Promise; Promise::reject('resolved1') ->catch(function (string $value) { // Show `resolved1` echo "resolved1\n"; });
Promise::reject(string)
驱动程序
您可以选择运行并发驱动程序。AsyncPromise实现了以下内容
- \AsyncPromise\Driver\SwooleDriver
- \AsyncPromise\Driver\FiberDriver
- \AsyncPromise\Driver\PcntlDriver (实验性)
- \AsyncPromise\Driver\PolyfillDriver
切换其他驱动程序
Promise::setPromiseDriver(\AsyncPromise\Driver\SwooleDriver::class); (new Promise(...))->then(...);
如果您使用SwooleDriver
,必须在Promise::createContext(...)
上下文中运行Promise。
Promise::setPromiseDriver(\AsyncPromise\Driver\SwooleDriver::class); Promise::createContext(function () { (new Promise(fn (callable $resolve) => $resolve('resolved with SwooleDriver'))) // Show `resolved with SwooleDriver` ->then(fn ($result) => print($result)); });
使用SwooleDriver
时,您将获得并发的好处。以下命令是获取SwooleDriver性能的命令
Promise::setPromiseDriver(\AsyncPromise\Driver\SwooleDriver::class); // sleep function to be coroutinized. \Swoole\Runtime::enableCoroutine(SWOOLE_HOOK_SLEEP); Promise::createContext(function () { $start = time(); Promise::all([ new Promise(function (callable $resolve) { sleep(3); $resolve(); }), new Promise(function (callable $resolve) { sleep(5); $resolve(); }), ])->then(function ($values) use ($start) { // Show `Take 5 sec` echo "Take " . (time() - $start) . " sec"; }); });
PolyfillDriver
是当没有安装并发驱动程序时的虚拟进程驱动程序。因此,PolyfillDriver
不会提高性能,因为它是在同步中运行的。例如,运行上述代码将显示“用时8秒”。
如何测试
您可以使用以下命令运行测试
./vendor/bin/phpunit tests/