Promises & Futures
Also Known As
TL;DR
Explanation
A Promise (JavaScript term) or Future (Java/PHP term) represents a computation that may not have completed yet. The object provides methods to attach callbacks that run when the value is ready (then/onFulfilled) or when an error occurs (catch/onRejected). Promises solve callback hell — the pyramid of nested callbacks that becomes unreadable when composing multiple async operations. In JavaScript, Promises are built-in and async/await is syntactic sugar over them. In PHP, Promises appear in ReactPHP and Guzzle — Guzzle's async HTTP client returns PromiseInterface objects that can be composed with Utils::all() for parallel requests. PHP Fibers (8.1+) provide a lower-level cooperative multitasking primitive that async frameworks use internally. The key distinction: a Promise represents a result that will be ready; a Future is a handle to cancel or check the status of the operation as well.
Common Misconception
Why It Matters
Common Mistakes
- Forgetting to call $pool->promise()->wait() — creating async Guzzle requests without waiting for them means they never execute.
- Assuming PHP Promises provide thread-level parallelism — they provide I/O concurrency, not CPU parallelism.
- Not handling Promise rejections — an unhandled rejection silently swallows errors in some implementations; always attach a catch handler.
- Mixing synchronous and async code without understanding when execution occurs — a Promise callback runs when the event loop processes it, not immediately.
Code Examples
// Sequential — total time = sum of all request times
$client = new GuzzleHttp\Client();
$user = $client->get('/api/user/' . $id)->getBody(); // 200ms
$orders = $client->get('/api/orders?user=' . $id)->getBody(); // 180ms
$prefs = $client->get('/api/prefs/' . $id)->getBody(); // 150ms
// Total: ~530ms
// Concurrent — total time = slowest single request
use GuzzleHttp\Client;
use GuzzleHttp\Utils;
$client = new Client();
$promises = [
'user' => $client->getAsync('/api/user/' . $id),
'orders' => $client->getAsync('/api/orders?user=' . $id),
'prefs' => $client->getAsync('/api/prefs/' . $id),
];
$results = Utils::unwrap(Utils::all($promises));
// All three fire simultaneously — total: ~200ms
$user = json_decode($results['user']->getBody(), true);
$orders = json_decode($results['orders']->getBody(), true);