Skip to content

Concurrent requests

Greg Bowler edited this page Mar 16, 2026 · 3 revisions

One of the main reasons to use this library is the ability to queue several requests and let them complete together.

Queue first, wait later

Here is the important pattern:

$http = new Http();

$http->fetch("https://example.com/profile");
$http->fetch("https://example.com/messages");
$http->fetch("https://example.com/notifications");

$http->wait();

Each fetch() call registers more work, but the script only blocks once wait() is called.

Independent promise chains

Each request can have its own chain of handlers.

$http->fetch("https://example.com/profile.json")
	->then(function(Response $response) {
		return $response->json();
	})
	->then(function($profile) {
		echo "Loaded profile", PHP_EOL;
	});

$http->fetch("https://example.com/avatar.jpg")
	->then(function(Response $response) {
		return $response->blob();
	})
	->then(function($blob) {
		echo "Loaded avatar", PHP_EOL;
	});

$http->wait();

There is no guarantee about the order in which those responses will complete, and usually that is exactly what we want.

Waiting for the whole batch

If we want one final callback after everything is done, all() makes that clear:

$http->fetch("https://example.com/a");
$http->fetch("https://example.com/b");

$http->all()->then(function() {
	echo "Done!", PHP_EOL;
});

Cancelling selected requests

Concurrent work becomes especially useful when combined with abort signals. We can give each request its own controller and then cancel only the ones we no longer need.

use GT\Fetch\AbortController;

$first = new AbortController();
$second = new AbortController();

$http->fetch("https://example.com/a.zip", ["signal" => $first->signal]);
$http->fetch("https://example.com/b.zip", ["signal" => $second->signal]);

$first->abort();
$http->wait();

The abort behaviour is described in more detail in cancelling requests.

Clone this wiki locally