【问题标题】:How do I "extract" the data from a ReactPHP\Promise\Promise?如何从 ReactPHP\Promise\Promise 中“提取”数据?
【发布时间】:2019-06-13 06:19:57
【问题描述】:

免责声明:这是我第一次使用 ReactPHP 和“php promises”,所以解决方案可能只是盯着我的脸 ????

我目前正在做一个需要创建 Slack 机器人的小项目。我决定使用Botman 包并使用它的 Slack RTM 驱动程序。该驱动程序利用 ReactPHP 的 Promise 与 RTM API 进行通信。

我的问题:

当我让机器人回复命令时,我想从 RTM API 中获取 get 检索响应,这样我就可以缓存已发布消息的 ID。

问题是,响应是在其中一个ReactPHP\Promise\Promise 中返回的,但我根本不知道如何检索数据。

我在做什么:

所以当一个命令被触发时,机器人会发送一个回复 Slack:

$response = $bot->reply($response)->then(function (Payload $item) {
    return $this->reply = $item;
});

但是$response 包含一个(空的?)ReactPHP\Promise\Promise:

React\Promise\Promise^ {#887
  -canceller: null
  -result: null
  -handlers: []
  -progressHandlers: & []
  -requiredCancelRequests: 0
  -cancelRequests: 0
}

我也尝试过使用done() 而不是then(),这就是(据我所知)official ReactPHP docs suggest you should use to retrieve data from a promise:

$response = $bot->reply($response)->done(function (Payload $item) {
    return $this->reply = $item;
});

但随后$response 返回为null。

有趣的是,在调试过程中,我尝试在 then() 中执行 var_dump($item),但忘记删除 promise 上不存在的方法。但随后var_dump 居然返回了数据????

$response = $bot->reply($response)->then(function (Payload $item) {
    var_dump($item);
    return $this->reply = $item;
})->resolve();

所以据我所知,就好像我需要再次“执行”承诺,即使它在返回之前已经解决。

在 Bot 的回复方法中,这是发生了什么以及如何生成 ReactPHP 承诺:

public function apiCall($method, array $args = [], $multipart = false, $callDeferred = true)
{
    // create the request url
    $requestUrl = self::BASE_URL . $method;

    // set the api token
    $args['token'] = $this->token;

    // send a post request with all arguments
    $requestType = $multipart ? 'multipart' : 'form_params';
    $requestData = $multipart ? $this->convertToMultipartArray($args) : $args;

    $promise = $this->httpClient->postAsync($requestUrl, [
        $requestType => $requestData,
    ]);

    // Add requests to the event loop to be handled at a later date.
    if ($callDeferred) {
        $this->loop->futureTick(function () use ($promise) {
            $promise->wait();
        });
    } else {
        $promise->wait();
    }

    // When the response has arrived, parse it and resolve. Note that our
    // promises aren't pretty; Guzzle promises are not compatible with React
    // promises, so the only Guzzle promises ever used die in here and it is
    // React from here on out.
    $deferred = new Deferred();
    $promise->then(function (ResponseInterface $response) use ($deferred) {
        // get the response as a json object
        $payload = Payload::fromJson((string) $response->getBody());

        // check if there was an error
        if (isset($payload['ok']) && $payload['ok'] === true) {
            $deferred->resolve($payload);
        } else {
            // make a nice-looking error message and throw an exception
            $niceMessage = ucfirst(str_replace('_', ' ', $payload['error']));
            $deferred->reject(new ApiException($niceMessage));
        }
    });

    return $deferred->promise();
}

你可以看到它的完整来源here。

请给我指明一个方向。我觉得我什么都试过了,但显然我错过了什么或做错了什么。

【问题讨论】:

    标签: php promise slack-api reactphp


    【解决方案1】:

    ReactPHP 核心团队成员在这里。这里有一些选择和事情。

    首先,then 永远不会从 Promise 中返回值,它会返回一个新的 Promise,因此您可以创建一个 Promise 链。因此,您在每个 then 中执行一个新的异步操作,该操作会接收前一个操作的结果。

    其次,done 从不返回结果值,其工作方式与then 非常相似,但会从链中的前一个 Promise 中抛出任何未捕获的异常。

    then 和done 的问题在于它们是您的解决方法。承诺 a 仅表示尚未完成的操作的结果。一旦操作准备好并解决了承诺,它将调用你手上的callablethen/done。所以最终你的所有操作都发生在callable 内,以一种或另一种方式,在最广泛的意义上。 (这也可以是类上的 __invoke 方法,具体取决于您的设置方式。这也是为什么我对 PHP 7.4 中的短闭包如此兴奋的原因。)

    你有两个选择:

    • 在callable's 中运行所有操作
    • 使用RecoilPHP

    前者意味着更多的思维导图和学习异步的工作原理以及如何围绕它进行思考。后者更容易,但需要您在协程中运行每个路径(callable 有一些很酷的魔法)。

    【讨论】:

    • 非常感谢您的解释。更有意义,我终于想出了我必须做什么:)
    • 很高兴听到这个消息!如果您还有任何问题,请随时与我们联系:)。
    猜你喜欢
    • 2020-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-09
    • 2020-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多