You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactPHP多API请求Promise无法正常resolve问题求助

解决ReactPHP中Guzzle异步请求与React\Promise\all()不resolve的问题

问题根源

Guzzle默认的异步请求使用自身的Promise实现,和ReactPHP的Promise体系不兼容,直接混用会导致React的Promise\all()无法正确追踪请求状态。而wait()是阻塞式等待Guzzle请求完成,相当于把异步转成同步执行,所以能工作,但完全违背了ReactPHP异步非阻塞的设计初衷。

解决方案

1. 使用Guzzle的ReactPHP适配器(推荐)

通过guzzlehttp/guzzle-react适配器,让Guzzle基于React事件循环执行异步请求,返回React兼容的Promise,从根源解决兼容性问题。

步骤:

  • 安装依赖:
composer require guzzlehttp/guzzle guzzlehttp/guzzle-react react/event-loop

示例代码:

<?php
require 'vendor/autoload.php';

use React\EventLoop\Factory;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Handler\CurlMultiHandler;
use React\Promise\all;

// 初始化React事件循环
$loop = Factory::create();

// 配置Guzzle使用React驱动的CurlMultiHandler
$handler = new CurlMultiHandler();
$handler->setLoop($loop);
$stack = HandlerStack::create($handler);
$client = new Client(['handler' => $stack]);

// 构建多个异步请求的Promise数组
$apiPromises = [];
for ($i = 0; $i < 5; $i++) {
    $apiPromises[] = $client->getAsync("https://api.example.com/item/{$i}")
        ->then(function ($response) {
            // 解析响应结果,按需处理
            return json_decode((string)$response->getBody(), true);
        });
}

// 用React\Promise\all()批量处理所有请求
all($apiPromises)
    ->then(function ($allResults) {
        // 所有请求成功完成,处理结果集
        foreach ($allResults as $idx => $result) {
            echo "请求 {$idx} 响应:" . print_r($result, true) . PHP_EOL;
        }
    })
    ->otherwise(function ($error) {
        // 任意一个请求失败时触发
        echo "请求错误:" . $error->getMessage() . PHP_EOL;
    });

// 启动事件循环,异步执行所有请求(必须调用,否则Promise不会触发)
$loop->run();

2. 手动转换Guzzle Promise为React Promise

如果不想引入额外适配器,可手动将Guzzle的Promise包装成React兼容的Promise:

<?php
require 'vendor/autoload.php';

use React\EventLoop\Factory;
use React\Promise\Deferred;
use GuzzleHttp\Client;
use React\Promise\all;

$loop = Factory::create();
$client = new Client();

$apiPromises = [];
for ($i = 0; $i < 5; $i++) {
    $deferred = new Deferred();
    
    // 发起Guzzle异步请求,绑定状态到React的Deferred
    $client->getAsync("https://api.example.com/item/{$i}")
        ->then(
            function ($response) use ($deferred) {
                $deferred->resolve(json_decode((string)$response->getBody(), true));
            },
            function ($error) use ($deferred) {
                $deferred->reject($error);
            }
        );
    
    $apiPromises[] = $deferred->promise();
}

// 批量处理Promise
all($apiPromises)
    ->then(function ($allResults) {
        foreach ($allResults as $idx => $result) {
            echo "请求 {$idx} 响应:" . print_r($result, true) . PHP_EOL;
        }
    })
    ->otherwise(function ($error) {
        echo "请求错误:" . $error->getMessage() . PHP_EOL;
    });

$loop->run();

3. 关键注意事项

  • 必须启动React事件循环:所有ReactPHP异步操作依赖事件循环,最后一定要调用$loop->run(),否则Promise永远不会触发resolve/reject。
  • 禁止使用wait():wait()会阻塞事件循环,完全破坏异步非阻塞的特性,仅用于调试或同步场景。
  • 统一Promise体系:确保所有传入React\Promise\all()的Promise都属于React的Promise体系,避免不同实现混用。

内容的提问来源于stack exchange,提问作者Philipp Braun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 15:22:43