当前位置: 首页 > 知识库问答 >
问题:

在大炮中处理每个promise(each_limit)的总promise

孟俊晖
2023-03-14

假设我们有一个API POSTendpoint,它返回如下答案:

{
  "data": [1,2,3],
  "total_rows": 20
}

这意味着我们收到了部分数据,只有3个条目的第一页。总条目数为20,这意味着我们希望在请求中使用一些偏移量调用其他页面。因此,总计数(以及可能的偏移量)只有在第一次调用完成后才知道,而其他调用并不相互依赖,可以同时完成。

它是PHP,对于这个任务,Guzzle6与Promises/A一起使用。此外,Guzzes提供了EachPromise类,该类接收多个promise的迭代和用于设置处理的配置哈希。根据类构造函数的PhpDoc块:

配置哈希可以包括以下键值对:

  • 已履行:(可调用)在promise履行时调用。调用该函数时有三个参数:履行值、promise的iterable列表中的索引位置,以及管理所有promise的聚合promise。聚合promise可以
    从回调内部解决,以缩短promise
$paginatedResult = $this->client->sendAsync($this->createRequest($requestBody))
    ->then(function (ResponseInterface $response) use ($requestBody) {
            return $this->deserializeToPaginatedResult(
                $response,
                $requestBody->paginatedResultClass()
            );
        }
    )->wait();

$pageGenerator = function () use ($paginatedResult, $requestBody) {
    $perPageCount = count($paginatedResult->getItems());
    $totalItems = $paginatedResult->getTotalCount();

    for ($currentOffset = $perPageCount; $currentOffset <= $totalItems; $currentOffset += $perPageCount) {
        $newRequestBody = clone $requestBody;
        $newRequestBody->setOffset($currentOffset);

        yield $this->client->sendAsync($this->createRequest($newRequestBody));
    }
};

$aggregatedResult = (new EachPromise(
    $pageGenerator(), [
        'concurrency' => 4,
        'fulfilled' => function ($promiseResult, $promiseIndex, $promiseAggregate) use ($requestBody) {
            $paginatedResult = $this->deserializeToPaginatedResult(
                $promiseResult,
                $requestBody->paginatedResultClass()
            );

            return $paginatedResult->getItems();
        },
    ]
))->promise()
    ->then(
        function ($promisedAggregatedResult) {
            var_dump($promisedAggregatedResult);
        }
    )
    ->wait();

var_dump($aggregatedResult);

在配置散列中,completed回调接收3个对象,如文档所述。可以正确处理$promiseResult,并且$paginatedResult-

应该如何正确地使用古斯的每个promise(以及它的助手函数)来聚合传递给它的所有promise的结果?


共有2个答案

甄飞飙
2023-03-14
匿名用户

您也可以使用池::batch()方法,它在内部执行几乎相同的操作。

$pageGenerator = function () use (...) {
    // ...
    yield $this->createRequest($newRequestBody);
    // ...
}

$responses = Pool::batch($this->client, $pageGenerator(), ['concurrency' => 4]);

章安宜
2023-03-14

根据各Promise类别说明:

表示对多个promise进行迭代并在流程中调用副作用函数的promise。

因此,这些配置哈希可调用函数只是副作用函数,可能会或可能不会短路解决聚合promise。这正是实现函数既不影响$promiseggregate,也不以最后一个可实现调用的参数$promisedAggregatedResult结束的原因。

关于正确用法的提示可以在\GuzzleHttp\Promise\all\GuzzleHttp\Promise\some函数中找到。关键的想法是在那些副作用实现的回调中通过引用使用外部聚合。如果聚合promise从未在这些副作用函数中解析,那么它将解析为null,然后在下一个然后履行回调中传递。同样,应该在可调用的实现中使用通过引用聚合,以便将其作为promise实现值返回。

$paginatedResult = $this->client->sendAsync($this->createRequest($requestBody))
    ->then(function (ResponseInterface $response) use ($requestBody) {
            return $this->deserializeToPaginatedResult(
                $response,
                $requestBody->paginatedResultClass()
            );
        }
    )->wait();

$pageGenerator = function () use ($paginatedResult, $requestBody) {
    $perPageCount = count($paginatedResult->getItems());
    $totalItems = $paginatedResult->getTotalCount();

    for ($currentOffset = $perPageCount; $currentOffset <= $totalItems; $currentOffset += $perPageCount) {
        $newRequestBody = clone $requestBody;
        $newRequestBody->setOffset($currentOffset);

        yield $this->client->sendAsync($this->createRequest($newRequestBody));
    }
};
$items = $paginatedResult->getItems();

return each_limit(
    $pageGenerator(),
    4,
    function ($promiseResult) use (&$items, $requestBody) {
        $paginatedResult = $this->deserializeToPaginatedResult(
            $promiseResult,
            $requestBody->paginatedResultClass()
        );
        $items = array_merge($items, $paginatedResult->getItems());
    },
    function ($reason, $idx, PromiseInterface $aggregate) {
        $aggregate->reject($reason);
    })->then(function () use (&$items) {
        ksort($items);
        return $items;
    });

 类似资料:
  • 本文向大家介绍AngularJS中处理多个promise的方式,包括了AngularJS中处理多个promise的方式的使用技巧和注意事项,需要的朋友参考一下 在使用AngularJS中处理promise的时候,有时会碰到需要处理多个promise的情况。 最简单的处理就是每个promise都then。如下: 有没有更好的方式? $q.all方法可以接受promise的一个数组,按如下调用: 什么

  • 我一直得到“UnhandledPromiseRejectionWarning:UnhandledPromiseRejection.此错误源于在没有catch块的异步函数内部抛出,或拒绝未用.catch()处理的Promission.(拒绝ID:2)” 我已经处理了所有的承诺,但错误仍然存在

  • 问题内容: 我需要构建一个函数来处理大型CSV文件,以便在bluebird.map()调用中使用。考虑到文件的潜在大小,我想使用流媒体。 此函数应接受一个流(一个CSV文件)和一个函数(处理该流中的块),并在读取文件到末尾(已解决)或错误(已拒绝)时返回promise。 所以,我开始: 现在,我有两个相互关联的问题: 我需要限制正在处理的实际数据量,以免造成内存压力。 作为参数传递的函数通常将是异

  • 本文介绍了单个promise组合器: 但我没有看到的是,一种运行所有promise的方法,但不是在个人promise被拒绝时短路。我如何确保所有的promise都得到履行,但我能处理拒绝和所有promise的解决?

  • 我正在尝试使用节点在Discord上创建一个机器人。js模块不一致。js,在它的一个命令中,它遍历公会(服务器)中的成员地图,并将所有成员都禁用。以下是我使用的代码: 但是,如果一个成员没有连接到任何语音通道,setMute()方法创建的promise将被拒绝,并且在这里通过记录错误消息来处理它(同样,在实际代码中,拒绝被正确处理)。问题是,在拒绝之后,forEach会停止并不会执行,直到我再次执

  • 我得到这个错误- (节点:18420)未处理的PromisejectionWarning:TypeError:无法读取未定义的属性“name” (节点:18420)未处理的PromisejectionWarning:未处理的promise拒绝。此错误源于在没有catch块的情况下抛出异步函数的内部,或者拒绝使用未处理的promise。catch()。要在未处理的promise拒绝时终止节点进程,请