You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Description
If an EachPromise (or methods reliant of it like Each::of) is constructed with an empty iterable, it returns a promise in the pending state that only completes when waited on. In contrast, if the iterator has at least one item (even a fulfilled promise!) then it can be completed by running the queue.
It would be nice if things were more consistent. Either Each should always use the queue or it should complete synchronously if there is no async work to be done.
How to reproduce
// Empty case
$p = Each::of((function($b) { if ($b) { yield 1; } })(false));
$p->getState(); // "pending"
$p->then(function() { echo "DONE!"; });
\GuzzleHttp\Promise\Utils::queue()->run(); // does not print "DONE!"
// Non-empty case
$p = Each::of((function($b) { if ($b) { yield 1; } })(true));
$p->then(function() { echo "DONE!"; });
\GuzzleHttp\Promise\Utils::queue()->run(); // prints "DONE!"
Possible Solution
One solution would be to add the following code at the start of EachPromise::createPromise():
if (!$this->iterable->valid()) { return $this->aggregate = new FulfilledPromise(null); }
This way, it would complete synchronously with an empty iterator.
Additional context
The reason this is impacting me is that I'm using php fibers as a layer on top of Guzzle. When I want to wait on a promise, I need to pump the event loop (via CurlMultiHandler::tick()) to advance all promises until the current one is complete. This doesn't work if a promise becomes "orphaned" such that it is neither complete nor completable via the queue or the curl handler.
The text was updated successfully, but these errors were encountered:
PHP version: 8.2.12 (hint:
php --version
)Description
If an
EachPromise
(or methods reliant of it likeEach::of
) is constructed with an empty iterable, it returns a promise in the pending state that only completes when waited on. In contrast, if the iterator has at least one item (even a fulfilled promise!) then it can be completed by running the queue.It would be nice if things were more consistent. Either Each should always use the queue or it should complete synchronously if there is no async work to be done.
How to reproduce
Possible Solution
One solution would be to add the following code at the start of
EachPromise::createPromise()
:This way, it would complete synchronously with an empty iterator.
Additional context
The reason this is impacting me is that I'm using php fibers as a layer on top of Guzzle. When I want to wait on a promise, I need to pump the event loop (via
CurlMultiHandler::tick()
) to advance all promises until the current one is complete. This doesn't work if a promise becomes "orphaned" such that it is neither complete nor completable via the queue or the curl handler.The text was updated successfully, but these errors were encountered: