Promise\_php 的 then() 仅处理 resolved 状态且不返回新 Promise,必须紧跟 catch() 捕获 reject 错误;resolve/reject 参数需严格为标量或 Exception;混用 futureTick() 易导致时序错乱;all() 遇首个 reject 即终止并丢弃其余结果。

Promise\_php 的 then() 和 catch() 怎么配对用
Promise\_php 不是 Promise/A+ 实现,它没有链式 then() 自动返回新 Promise 的行为,直接套用 JS 写法会静默失败。它的 then() 只接受一个回调(成功),不支持第二个参数传失败处理 —— 想捕获错误必须显式调用 catch(),且必须在 then() 之后立即链上,否则异常不会被拦截。
-
then()的回调只在 Promise 状态为resolved时触发,参数是 resolve 的值;它本身返回的是原 Promise,不是新 Promise,不能继续链then() -
catch()必须紧跟在then()后调用(或直接跟在 Promise 创建后),否则抛出的异常会冒泡到 ReactPHP 事件循环并终止进程 - 如果 Promise 被 reject,但没写
catch(),你会看到类似React\Promise\Exception\RejectedException的未捕获异常,进程可能直接退出
示例:
$promise = new React\Promise\Promise(function ($resolve, $reject) {
// 模拟异步失败
\React\EventLoop\StreamSelectLoop::futureTick(function () use ($reject) {
$reject(new \Exception('Connection timeout'));
});
});
$promise
->then(function ($value) {
echo "success: $value";
})
->catch(function (\Exception $e) {
echo "error: " . $e->getMessage(); // ✅ 这里才能捕获
});
Promise\_php 的 resolve() 和 reject() 参数怎么传才安全
ReactPHP 的 Promise 构造器接收一个 executor 函数,里面通过闭包参数 $resolve 和 $reject 控制状态。这两个函数不是普通回调,它们对参数类型敏感:传入 Promise 实例会被自动展开(flattened),但传入 null、资源、闭包等非标量/非Promise 值,可能导致后续 then() 回调收不到值,甚至抛出 TypeError。
-
$resolve(42)、$resolve("ok")安全;$resolve(null)也合法,但下游then()会收到null,容易引发空指针 -
$resolve($anotherPromise)会等待其完成,这是标准行为;但若$anotherPromise是无效对象(比如未实例化),会立刻 throw -
$reject()推荐只传\Exception或其子类;传字符串或数组会导致catch()收到非 Exception 对象,instanceof \Exception判断失败
Promise\_php 和 ReactPHP 的 loop->futureTick() 混用要注意什么
很多人想用 futureTick() 模拟微任务来“降级” Promise 行为,但 Promise\_php 本身不依赖事件循环调度 —— 它的状态变更完全同步触发回调(只要 Promise 已 settled)。混用时最常见问题是:在 futureTick() 里 resolve 一个 Promise,却期望 then() 在当前 tick 执行,结果回调被推迟了一轮,逻辑时序错乱。
立即学习“PHP免费学习笔记(深入)”;
- Promise\_php 的
then()/catch()回调默认是同步执行的(如果 Promise 已完成);只有未完成的 Promise,回调才会被注册进 ReactPHP 的延迟队列 - 不要在
futureTick()中手动 resolve/reject 并期待“模拟 async/await”,这会让控制流更难推理 - 真正需要异步触发时,应使用
React\Promise\Deferred,它提供更清晰的 resolve/reject 分离和事件循环绑定
为什么 Promise\all() 失败时只返回第一个错误
React\Promise\all() 的行为和 JS 的 Promise.all() 不同:一旦任意一个 Promise reject,它立刻 reject 并只传递第一个错误,其余 Promise 的结果(包括其他错误)全部丢弃。这不是 bug,是设计选择 —— 它不收集全部错误,也不等待所有 Promise 结束。
- 如果你需要所有结果(成功+失败),得自己用
Promise\map()+ 每个加catch()包裹,把 reject 转成 success 返回数组 -
Promise\all()的参数必须是 Promise 实例数组;传入 null、空数组、含非-Promise 元素,会直接 throwInvalidArgumentException - 性能上,它不会并发限制,100 个 HTTP 请求全扔进去,会瞬间发起 —— 需要节流必须额外封装
复杂点在于:Promise\_php 的错误传播路径和 JS 直觉相反,而且没有 finally()、race() 等辅助方法,所有兜底逻辑都得手写补全。











