AbortController-mallit
AbortController ja AbortSignal ovat kohteessa Phasis täysin WHATWG-määrittelyn mukaisia toteutuksia. Myös määrittelyn mukaiset yhdistämisapufunktiot (AbortSignal.any, AbortSignal.timeout) sisältyvät. Tällä sivulla käsitellään yleisimmin tarvittavia toimintamalleja ja peruutuksen välittymistä kohteiden PHP välillä.
Fetch-pyynnön peruuttaminen
const ctrl = new AbortController();
const p = fetch(url, { signal: ctrl.signal });
ctrl.abort(); // p rejects with AbortError DOMException
Oletusarvo on AbortError, mutta voit antaa oman syysi:
ctrl.abort(new Error('user cancelled'));
fetch hylkää minkä tahansa välittämäsi arvon kanssa.
Aikakatkaisu
const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
AbortSignal.timeout(ms) palauttaa signaalin, joka keskeyttää itsensä ajan ms kuluttua. Ajastin toimii moottorin tapahtumasilmukan kautta. Sama silmukka ohjaa toimintoja setTimeout / queueMicrotask (katso API: Tapahtumasilmukka). Fetch-siirtotapa tarkistaa signaalin siirron aikana — oletusarvoisella CurlTransport-siirtotavalla tarkistus tehdään funktiolla CURLOPT_PROGRESSFUNCTION — joten pyyntö keskeytetään heti määräajan koittaessa.
Oletusarvoisesti silmukka toimii virtuaaliajassa: se siirtää kellonsa seuraavaan odottavaan määräaikaan sen sijaan, että odottaisi PHP, joten fetch(url, { signal: AbortSignal.timeout(5000) }) joko valmistuu ennen määräaikaa tai keskeytyy silmukan seuraavalla kierroksella — kohteen PHP odotusta ei koskaan viivästetä. Reaaliaikainen tahdistus edellyttää, että isäntä käyttää kohdetta tickEventLoop() seinäkellon mukaisesti.
Kilpailu: ensimmäinen peruutus voittaa
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
Välittyminen kerrosten läpi
Kääri oma asynkroninen työsi signaalin huomioivaan silmukkaan:
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;
}
Fetch perii signaalin suoraan; manuaalinen if (signal.aborted) kattaa pyyntöjen välit, joiden aikana sivun silmukka muuten jatkaisi suoritusta.
Keskeytystapahtuman kuuntelu
ctrl.signal.addEventListener('abort', () => {
releaseDatabaseLock();
cancelDownstreamWork();
});
signal.reason asetetaan ennen kuuntelijoiden käynnistymistä.
Signaali mukautetussa fetch-siirtotavassa
Jos vaihdat siirtotavan funktiolla setFetchTransport(), signaali välitetään kutsuttavalle JsObject-arvona. Huomioi se tarkistamalla:
$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',
);
}
// ...
});
Kun TransportException heitetään kohteessa kind: 'aborted', kohteen JS puolen fetch hylätään arvolla AbortError DOMException — aivan kuin määrittelyn mukainen keskeytyssilmukka olisi suoritettu.
Jos taustajärjestelmä tukee natiivia peruutusta (kohteen Guzzle on_progress, kohteen Symfony ResponseInterface::cancel), käytä samaa tarkista ja heitä -mallia.
Mallit, jotka eivät vielä toimi
signal.addEventListener('abort', () => fetch(cleanupUrl))— kuuntelijat suoritetaan synkronisesti; siivous-Fetch-pyyntö käynnistyy, mutta ei valmistu keskeytyksen käsittelyn aikana. Ajoita se ympäröivän kohteenawaitavulla.
setTimeout(() => ctrl.abort(), N) toimii (ajastinperhe sisältyy ja sen toiminta katetaan WPT-testeillä), mutta AbortSignal.timeout(N) on lyhyempi ja kertoo tarkoituksen selkeämmin, kun haluat vain keskeytyssignaalin määräajan jälkeen.
Katso myös
- Fetch-siirtotapa — mukautettujen siirtotapojen koko pyyntö-, vastaus- ja signaalirajapinta.
- Verkko-API:t (WPT) — AbortController/AbortSignal-testien läpäisyosuus WPT-testisarjassa.