Back to Promises

Promise Interoperability

docs/promise-interoperability.md

3.0.02.6 KB
Original Source

Promise Interoperability

This guide explains how Guzzle promises interact with foreign promise implementations. A foreign promise is any object with a then method, such as a React promise. When a foreign promise is returned from a then callback, Guzzle forwards resolution to that promise.

Foreign Promises

Capture the promise returned from then(). That chained promise is the Guzzle promise that follows the foreign promise's eventual result.

php
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\Utils;

$deferred = new React\Promise\Deferred();
$reactPromise = $deferred->promise();

$guzzlePromise = new Promise();
$chained = $guzzlePromise->then(function ($value) use ($reactPromise) {
    // Use the Guzzle value, then continue with the React promise.
    return $reactPromise;
});

$chained->then(function ($value) {
    echo $value;
});

$guzzlePromise->resolve('start');
Utils::queue()->run();

$deferred->resolve('done');
Utils::queue()->run();

Forwarding a foreign promise does not make Guzzle able to synchronously wait on or cancel the foreign operation. The chained Guzzle promise settles only after the foreign implementation invokes the callbacks registered through then(). If the foreign promise has no compatible wait() or cancel() behavior, Guzzle cannot invent that behavior.

Use Create::promiseFor($foreignPromise) to shadow a foreign thenable as a Guzzle promise. If the foreign object exposes wait() or cancel() methods, the wrapper uses them. Otherwise, use the foreign implementation's event loop or completion mechanism and drain Guzzle's task queue when callbacks need to run.

Event Loop Integration

Guzzle promises use a task queue to keep stack size constant and to run promise callbacks asynchronously. When waiting on promises synchronously, the task queue is automatically run while resolving the blocking promise and forwarded Guzzle promises.

When using promises asynchronously in an event loop, run the task queue on loop ticks. If you do not run the task queue, Guzzle promise callbacks may remain queued.

php
$queue = GuzzleHttp\Promise\Utils::queue();
$queue->run();

For example, you could use Guzzle promises with React using a short periodic timer. Avoid zero-interval timers because they may keep the loop busy even when there is no promise work to run.

php
$queue = GuzzleHttp\Promise\Utils::queue();
$loop = React\EventLoop\Factory::create();
$loop->addPeriodicTimer(0.01, [$queue, 'run']);