AbortControlleri mustrid
AbortController ja AbortSignal on Phasis-is täielikud WHATWG teostused. Ka standardi koostamise abifunktsioonid (AbortSignal.any, AbortSignal.timeout) on kaasas. See leht käsitleb levinud mustreid ja seda, kuidas tühistamine levib üle PHP piiri.
Fetch-päringu tühistamine
const ctrl = new AbortController();
const p = fetch(url, { signal: ctrl.signal });
ctrl.abort(); // p rejects with AbortError DOMException
Põhjus on vaikimisi AbortError, kuid võite määrata ka enda oma:
ctrl.abort(new Error('user cancelled'));
fetch lükatakse tagasi teie antud väärtusega.
Ajalimiit
const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
AbortSignal.timeout(ms) tagastab signaali, mis katkestab ise töö pärast aega ms. Taimer käivitub mootori sündmussilmuse kaudu, mis juhib ka setTimeout / queueMicrotask toiminguid (vt API: Sündmussilmus). Fetch-edastus kontrollib ülekande ajal signaali — vaikimisi CurlTransport puhul CURLOPT_PROGRESSFUNCTION kaudu —, seega katkestatakse päring kiiresti pärast tähtaja saabumist.
Vaikimisi kasutab tsükkel virtuaalaega: see viib kella järgmise ootel tähtajani, selle asemel et magada PHP, nii et fetch(url, { signal: AbortSignal.timeout(5000) }) kas lõpetab enne tähtaega või katkestatakse järgmisel tsüklitaktil — see ei jäta PHP kunagi ootama. Reaalajas toimimiseks peab host juhtima tickEventLoop() käitamist seinakella järgi.
Võidujooks: esimene katkestamine võidab
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
Leviku edasiandmine kihtide vahel
Mähi oma asünkroonne töö signaali arvestavasse tsüklisse:
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;
}
Päring pärib signaali otse; käsitsi tehtav if (signal.aborted) katab päringutevahelised pausid, mil lehe tsükkel muidu edasi töötaks.
Katkestussündmuse kuulamine
ctrl.signal.addEventListener('abort', () => {
releaseDatabaseLock();
cancelDownstreamWork();
});
signal.reason määratakse enne kuulajate käivitamist.
Signaal kohandatud päringu transpordis
Kui vahetate transpordi välja setFetchTransport() kaudu, antakse signaal teie väljakutsutavale funktsioonile kui JsObject. Arvestage sellega, kontrollides seda perioodiliselt:
$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',
);
}
// ...
});
kind: 'aborted' abil TransportException viskamine paneb JS-poole fetch-i tagasi lükkama veaga AbortError DOMException — sama juhtub siis, kui spetsifikatsioonikohane katkestustsükkel oleks käivitunud.
Natiivset katkestamist toetavate taustateenuste puhul (Guzzle on_progress, Symfony ResponseInterface::cancel) kasutage sama perioodilise kontrolli ja vea viskamise mustrit.
Mustreid, mis veel ei tööta
signal.addEventListener('abort', () => fetch(cleanupUrl))— kuulaja käivitatakse sünkroonselt; puhastuspäring küll algab, kuid katkestuse töötlemise ajal ei jõua lõpule. Ajastage see ümbritsevaawaitkaudu.
setTimeout(() => ctrl.abort(), N) töötab (taimerite perekond on kaasas ja WPT-ga kaetud), kuid AbortSignal.timeout(N) on lühem ja väljendab kavatsust paremini, kui soovite vaid tähtaja saabudes katkestava signaali.
Vt ka
- Päringutransport — kohandatud transpordi täielik päringu, vastuse ja signaali liides.
- Veebi API-d (WPT) — AbortControlleri ja AbortSignali WPT läbimise määr.