amonite / async
PHP 异步、await 和 Promise 类,准备运行异步方法
Requires
- php: >=7.2
This package is not auto-updated.
Last update: 2024-10-02 16:11:33 UTC
README
PHP 的异步范式!
现在可以使用了!只需使用 await
函数开始您的异步环境,然后使用下面的函数和类做您想做的事情!
安装
您可以选择以下方法:
- 运行
composer require amonite/async
,或者 - 将
async.phar
文件复制到您的项目目录中,并使用require
加载它。
上下文
作为一名 JavaScript 开发者,我喜欢异步范式。我决定将这种范式导出,以便 PHP 可以利用它:现在,可以创建在等待它们加载数据时处理信息的库。
非阻塞事件
在 PHP 中,默认情况下,许多函数会在脚本结束时停止。这对常见的算术函数很有帮助,但您还可以在您从数据库请求数据时观察到它(无论您的软件是什么),当您从您的计算机或互联网加载文件时,当您使用某些套接字或运行命令行时。
当您的脚本等待另一个软件时,那么您的进程就会停止。当客户端开始向服务器发送请求时,它会等待上一个客户端脚本结束。当成千上万的客户端都在等待单个客户端,而该客户端正在等待一个耗时 30 秒以上的单个重 SQL 请求时,服务器可能会崩溃,就像遭受了 DDoS 攻击一样。
通过使用这个库,我将开发一个非阻塞 HTTP 服务器,然后是 HTTPS、HTTP/2、SQL 和文件系统读写器。希望这能有所帮助!
用法
理解 await/async 环境
函数 await
创建一个环境,允许注册一个 async
事件。异步事件是一个非阻塞函数,它在写入文件函数、读取文件函数、连接启动函数等结束时继续脚本。
创建 await 环境
在 await($fn_env) : mixed
中的函数 $fn_env
创建了一个异步环境,并等待(许多次)所有异步事件结束。在此函数中,脚本在它的异步函数结束之前被阻塞。如果 $fn_env
返回一个 Promise
,则 await
函数返回其已解决的答案或抛出其已拒绝的错误。
文件包装 test/wrap.php
<?php require_once "async.phar"; //require_once "index.php"; await(function () { require "await.php"; require "async.php"; });
触发异步事件
在 async($test, $then) : null
中的函数 $test
在 await
函数的每次迭代中执行,直到它返回一个真值(或抛出一个错误)。
这里的文件 wrap
允许使用异步函数的所有必需文件。
在下一个文件中,我同时使用了异步和 await。首先注册异步,然后等待 await
函数结束和异步事件,然后注册最后一个异步函数。
文件 test/await.php
<?php $date = microtime(true); async(function () use ($date) { if($date + 4 < microtime(true)) return true; }, function ($err) { if ($err) echo "err:$err\n"; echo "first resolved\n"; }); echo "first entered\n"; await(function () use ($date) { async(function () use ($date) { if($date + 3 < microtime(true)) return true; }, function ($err) { if ($err) echo "err:$err\n"; echo "second resolved\n"; }); echo "second entered\n"; async(function () use ($date) { if($date + 2 < microtime(true)) return true; }, function ($err) { if ($err) echo "err:$err\n"; echo "third resolved\n"; }); echo "third entered\n"; }); async(function () use ($date) { if($date + 1 < microtime(true)) return true; }, function ($err) { if ($err) echo "err:$err\n"; echo "fourth resolved\n"; }); echo "fourth entered\n";
控制台将打印
(t+0s) > first entered
(t+0s) > second entered
(t+0s) > third entered
(t+2s) > third resolved
(t+3s) > second resolved
(t+3s) > fourth entered
(t+3s) > fourth resolved
(t+4s) > first resolved
使用 Promise 类
Promises 通常用于平坦异步和冗长的函数。它遵循 JavaScript 标准。
文件 test/promise.php
<?php require_once __DIR__ . "/../index.php"; $date = microtime(true); $p = new Async\Promise(function ($resolve, $reject) use ($date) { while (microtime(true) < $date + 2) time_nanosleep(0,1); $resolve(); }); $p->then(function () { echo "I waited for 2 seconds.\n"; throw new Error("test error"); }); $p->catch(function () { echo "An error occurred in the promise or in then() function.\n"; }); var_dump(await(function () use ($date) { return Async\Promise::all(array( Async\Promise::resolve(3.14), Async\Promise::async(function () { return "Fibonacci"; }), Async\Promise::async(function () use ($date) { if (microtime(true) > $date + 3) return "Time elapsed!"; }) )); }));
(!) 在此示例中,代码在 2 秒钟后才会阻塞,然后等待每个 Promise
被解决。
使用 Async 类
如果您想完全管理您的异步事件,您可能更喜欢使用 Async 类。
文件 test/async.php
<?php $delay = microtime(true) + 3; $test = function () use ($delay) { if ($delay < microtime(true)) return "delay"; }; $then = function ($err, $m) { if ($err) { echo "$err err"; } else { echo "$m then\n"; } }; new Async\Async($test, $then);
在阻塞上下文中的返回
现在你已经处理了异步项目,你可以回到同步脚本中,使用它的阻塞函数和它的时间浪费。幸运的是!你可以在其环境中通过返回一个 Promise
来获取 await
值。函数 await
能够获取返回的 Promise 的结果。警告:如果您的 Promise 被拒绝,那么 await
将会抛出错误!
文件 test/await_async.php
<?php require_once "index.php"; $res = await(function () { // do async stuff // ... return new Async\Promise(function (\Closure $resolve, \Closure $reject) { $d = 3; $t = microtime(true) + $d; async(function () use ($t){ return microtime(true) > $t; }, function ($err) use ($resolve, $reject, $d) { if ($err) $reject($err); else $resolve("Now $d seconds elapsed. Well done!\n"); }); }); }); echo $res;
文档
函数 await
创建一个异步实例并在 await 环境中注册它。
- 语法:
await (\Closure $env) : mixed
- 参数:
$env {Closure.<$self {Closure}>}
是一个用于注册每个异步实例的函数。 - 返回: 如果
$env
返回一个已解析的 Promise,则返回其结果。 - 抛出: 如果
$env
抛出或返回一个被拒绝的 Promise(返回其错误)。
函数 async
注册一个在每个 await
环境的每个滴答等待解决或拒绝的函数或超时错误(如果没有设置,则为 3000ms)。
- 语法:
async (\Closure $test, \Closure $then = null) : null
- 参数
$fn {Closure.<>}
是在每个await
环境中执行的第一个函数,直到它返回一个真值,作为第二个参数发送到$then
;如果函数抛出错误,则将其作为第一个参数发送到$then
。$then {Closure.<$error {Throwable|null}, $result {*}>}
是在$fn
事件发生后执行的函数;当$fn
解决时,结果作为第二个参数$result
发送,或者当$fn
抛出错误时,错误作为第一个参数$error
发送(否则$error
为null
)。
- 返回:
null
。 - 抛出: 如果此实例不是在
await
环境中创建的,则抛出{Async\AsyncError}
。
类 Async\Await
方法 __construct
创建一个异步实例并在 await 环境中注册它。
- 语法:
$await = new Async\Await (\Closure $env) : {Async\Await}
- 参数:
$env {Closure.<$self {Closure}>}
是一个用于注册每个异步实例的函数。 - 返回:
{Async\Await}
新实例。 - 抛出: 如果
$env
抛出,则抛出{Throwable}
。
方法 env
在 await 环境中运行函数,并将 $env
中找到的异步实例添加进去。
- 语法:
$await->env (\Closure $env) : mixed
- 参数:
$env {Closure.<$self {Closure}>}
是一个用于注册每个异步实例的函数。 - 返回: 如果
$env
返回一个已解析的 Promise,则返回其结果。 - 抛出: 如果
$env
抛出或返回一个被拒绝的 Promise(返回其错误)。
静态 isAwaitContext
判断您的脚本是否当前在 await
环境中。
- 语法:
Async\Await::isAwaitContext() : boolean
- 返回:
{boolean}
如果脚本在 await 环境中,则为true
。
静态 add
静态 remove
类 Async\Async
方法 __construct
注册一个在每个 await
环境的每个滴答等待解决或拒绝的函数或超时错误(如果没有设置,则为 3000ms)。
- 语法:
$async = new Async\Async (\Closure $test, \Closure $then = null) : Async\Async
- 参数
$test {Closure.<>}
是在每个await
环境中执行的第一个函数,直到它返回一个真值,作为第二个参数发送到$then
;如果函数抛出错误,则将其作为第一个参数发送到$then
。$then {Closure.<$error {Throwable|null}, $result {*}>}
是在$test
事件发生后执行的函数;当$test
解决时,结果作为第二个参数$result
发送,或者当$test
抛出错误时,错误作为第一个参数$error
发送(否则$error
为null
)。
- 返回:
{Async\Async}
新实例。 - 抛出: 如果此实例不是在
await
环境中创建的,则抛出{Async\AsyncError}
。
方法 test
验证 $test
函数返回一个真值:如果是真值,则执行 $then
函数;否则什么也不做;或者捕获错误并发送到 $then
函数。
- 语法:
$async->test()
- 返回:
{Async\Async}
此实例。
类 Async\Promise
方法 __construct
创建一个 Promise 实例。Promise 帮助将异步函数扁平化到单个实例中。
- 语法:
$prom = new Async\Promise(\Closure $fn) : Async\Promise
- 参数:
$fn {Closure.<$resolve {Closure.<$result {*}>}, $reject {Closure.<$error {Throwable}>}>}
是等待$resolve
执行或$reject
执行或错误抛出的函数。 - 返回值:
{Async\Promise.<$result {*}>.<$error {Throwable}>}
新实例。
方法 then
注册一个函数,当Promise解析时执行。
- 语法:
$prom->then(\Closure $fn)
- 参数:
$fn {Closure.<$result {*}>}
是当Promise解析时执行的函数。将$result
值传递给$resolve
。 - 返回值:
{Async\Promise}
自身实例。
方法 catch
注册一个函数,当Promise拒绝时执行。
- 语法:
$prom->then(\Closure $fn)
- 参数:
$fn {Closure.<$error {Throwable}>}
是当Promise拒绝时执行的函数。将$error
值传递给$reject
。 - 返回值:
{Async\Promise}
自身实例。
方法 finally
注册一个函数,在Promise解析或拒绝后执行。
- 语法:
$prom->then(\Closure $fn)
- 参数:
$fn {Closure.<$result {*}>}
是在Promise解析或拒绝后执行的函数。将$result
值传递给$resolve
或在$reject
中。 - 返回值:
{Async\Promise}
自身实例。
静态 resolve
创建已解析Promise的有用函数。
- 语法:
Async\Promise::resolve($result {*})
- 参数:
$result {*}
是解析的值 - 返回值:
{Async\Promise}
新实例。
静态 reject
创建已拒绝Promise的有用函数。
- 语法:
Async\Promise::resolve($error {*})
- 参数:
$error {Throwable}
是拒绝的值 - 返回值:
{Async\Promise}
新实例。
静态 all
创建等待Promise列表$list
解析的有用函数。
- 语法:
Async\Promise::all($list)
- 参数:
$list {Array.<{Async\Promise} ...>}
应该解析的Promise列表。 - 返回值:
{Array.<{*} ...>}
每个Promise的答案。
静态 any
创建等待Promise列表$list
中任何一个解析的有用函数。
- 语法:
Async\Promise::any($list)
- 参数:
$list {Array.<{Async\Promise} ...>}
可解析的Promise列表。 - 返回值:
{*}
第一个解析的Promise的答案。