Schemi d'uso di AbortController
AbortController e AbortSignal sono implementazioni WHATWG complete in Phasis. Sono inclusi anche gli helper standard di composizione (AbortSignal.any, AbortSignal.timeout). Questa pagina illustra gli schemi più utili e il modo in cui l'annullamento si propaga attraverso il confine PHP.
Annullare una richiesta fetch
const ctrl = new AbortController();
const p = fetch(url, { signal: ctrl.signal });
ctrl.abort(); // p rejects with AbortError DOMException
Il motivo predefinito è AbortError, ma potete specificarne uno vostro:
ctrl.abort(new Error('user cancelled'));
fetch viene rifiutato con il valore passato.
Timeout
const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
AbortSignal.timeout(ms) restituisce un segnale che si annulla automaticamente dopo ms. Il timer scatta tramite l'event loop del motore, lo stesso che gestisce setTimeout / queueMicrotask (consultate API: Event loop). Il trasporto fetch controlla il segnale durante il trasferimento — per il valore predefinito CurlTransport, tramite CURLOPT_PROGRESSFUNCTION — quindi la richiesta viene annullata prontamente alla scadenza.
Per impostazione predefinita, il loop usa il tempo virtuale: porta avanti l'orologio fino alla prossima scadenza, invece di attendere PHP. Così una fetch(url, { signal: AbortSignal.timeout(5000) }) termina prima della scadenza oppure viene annullata al tick successivo del loop: non costringe mai PHP ad aspettare. Per scandire il tempo reale, l'host deve eseguire tickEventLoop() in base a un orologio reale.
Race: prevale il primo annullamento
const user = new AbortController();
const signal = AbortSignal.any([user.signal, AbortSignal.timeout(10_000)]);
const res = await fetch(url, { signal });
// res rejects if EITHER the user clicks cancel OR 10s elapses
Propagazione attraverso i livelli
Avvolgete il vostro lavoro asincrono in un loop che controlla il segnale:
async function fetchPaged(url, signal) {
const out = [];
for (let page = 1; ; page++) {
if (signal.aborted) throw signal.reason;
const r = await fetch(`${url}?page=${page}`, { signal });
const data = await r.json();
if (data.length === 0) break;
out.push(...data);
}
return out;
}
La richiesta fetch eredita direttamente il segnale; l'uso manuale di if (signal.aborted) copre gli intervalli tra le richieste, durante i quali il loop della pagina continuerebbe altrimenti a funzionare.
Ascoltare l'evento di annullamento
ctrl.signal.addEventListener('abort', () => {
releaseDatabaseLock();
cancelDownstreamWork();
});
signal.reason viene impostato prima che vengano eseguiti i listener.
Segnale in un trasporto fetch personalizzato
Se sostituite il trasporto tramite setFetchTransport(), il segnale viene passato al vostro callable come JsObject. Per rispettarlo, controllatelo periodicamente:
$engine->setFetchTransport(function (array $req, $signal) {
$ch = curl_init($req['url']);
// ...
if ($signal !== null) {
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION,
fn () => $signal->get('aborted')->value ? 1 : 0);
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
}
$body = curl_exec($ch);
if (curl_errno($ch) === CURLE_ABORTED_BY_CALLBACK) {
throw new \Phasis\BuiltIn\Fetch\TransportException(
'aborted', 'aborted',
);
}
// ...
});
Lanciare TransportException con kind: 'aborted' fa sì che il lato JS di fetch venga rifiutato con AbortError DOMException, come se fosse stato eseguito il ciclo di annullamento previsto dalle specifiche.
Per i backend con annullamento nativo (Guzzle di on_progress, ResponseInterface::cancel di Symfony), usate lo stesso schema di controllo e lancio dell'errore.
Schemi che ancora non funzionano
signal.addEventListener('abort', () => fetch(cleanupUrl))— i listener vengono eseguiti in modo sincrono; la richiesta fetch di pulizia si avvia, ma non può completarsi durante la gestione dell'annullamento. Pianificatela tramiteawait.
setTimeout(() => ctrl.abort(), N) funziona (la famiglia dei timer è inclusa e verificata dai WPT), ma AbortSignal.timeout(N) è più breve e comunica meglio l'intento quando volete soltanto un segnale di annullamento alla scadenza.
Vedi anche
- Trasporto fetch — interfaccia completa per richieste, risposte e segnali per i trasporti personalizzati.
- API web (WPT) — percentuale di superamento dei WPT per AbortController/AbortSignal.