AbortController-minták
A AbortController és a AbortSignal teljes WHATWG-megvalósítás a Phasis-ben. A szabványos kompozíciós segédek (AbortSignal.any, AbortSignal.timeout) is rendelkezésre állnak. Ez az oldal a gyakran használt mintákat mutatja be, és azt, hogyan terjed tovább a megszakítás az PHP határán.
Fetch megszakítása
const ctrl = new AbortController();
const p = fetch(url, { signal: ctrl.signal });
ctrl.abort(); // p rejects with AbortError DOMException
Az ok alapértelmezés szerint AbortError, de megadhat sajátot:
ctrl.abort(new Error('user cancelled'));
A fetch azzal utasítja el a kérést, amit átadott neki.
Időkorlát
const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
A AbortSignal.timeout(ms) olyan jelet ad vissza, amely ms elteltével önmagát megszakítja. Az időzítő a motor eseményciklusán keresztül lép működésbe, ugyanazon keresztül, amely a setTimeout / queueMicrotask elemeket is vezérli (lásd: API: Eseményciklus). A fetch-átviteli mód az átvitel során ellenőrzi a jelet — az alapértelmezett CurlTransport esetén a CURLOPT_PROGRESSFUNCTION segítségével —, így a kérés a határidő lejártakor gyorsan megszakad.
Az eseményciklus alapértelmezés szerint virtuális idejű: a következő függő határidőre állítja az órát, ahelyett hogy PHP-ig várakozna, így a fetch(url, { signal: AbortSignal.timeout(5000) }) vagy a határidő előtt fejeződik be, vagy az eseményciklus következő lépésénél megszakad — a PHP-nek sosem kell várnia. A valós idejű ütemezéshez a gazdának falióra szerint kell vezérelnie az tickEventLoop()-et.
Verseny: az első megszakítás nyer
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
Továbbterjedés a rétegeken át
Jelérzékeny ciklussal csomagolja be a saját aszinkron feladatait:
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;
}
A fetch közvetlenül örökli a jelet; a kézi if (signal.aborted) kezeli a kérések közötti szüneteket, amikor az oldal ciklusa egyébként tovább futna.
Figyelés a megszakítási eseményre
ctrl.signal.addEventListener('abort', () => {
releaseDatabaseLock();
cancelDownstreamWork();
});
A signal.reason már be van állítva, mielőtt a figyelők lefutnak.
Jel egy egyéni fetch-átviteli módban
Ha az átviteli módot a setFetchTransport() használatával cseréli le, a jel JsObject formájában jut el a hívható elemhez. A megszakítás érvényesítéséhez rendszeresen ellenőrizze:
$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',
);
}
// ...
});
Ha kind: 'aborted'-gyel TransportException-t dob, a JS oldali fetch AbortError DOMException-vel utasítja el a kérést — ugyanúgy, mintha a specifikáció megszakítási ciklusa lefutott volna.
A natív megszakítást támogató háttérrendszerek esetén (a Guzzle on_progress-ja, illetve a Symfony ResponseInterface::cancel-ja) alkalmazza ugyanezt az ellenőrzési és kivételdobási mintát.
Még nem működő minták
signal.addEventListener('abort', () => fetch(cleanupUrl))— a figyelők szinkron módon futnak le; a takarító fetch elindul, de a megszakítás eseményének feldolgozása alatt nem fejeződik be. Ütemezze a környezőawaitsegítségével.
A setTimeout(() => ctrl.abort(), N) működik (az időzítők rendelkezésre állnak, és a WPT lefedi őket), de a AbortSignal.timeout(N) rövidebb, és jobban kifejezi a szándékot, ha csak egy határidő után megszakító jelre van szüksége.
Lásd még
- Fetch-átvitel — teljes kérés-/válasz-/jelinterfész egyéni átviteli módokhoz.
- Webes API-k (WPT) — az AbortController/AbortSignal WPT-sikerességi aránya.