AbortController lietošanas paņēmieni
AbortController un AbortSignal ir pilnas WHATWG implementācijas Phasis. Ir pieejami arī standarta kompozīcijas palīgrīki (AbortSignal.any, AbortSignal.timeout). Šajā lapā aplūkoti biežāk izmantotie paņēmieni un tas, kā atcelšana izplatās pāri PHP robežai.
Fetch pieprasījuma atcelšana
const ctrl = new AbortController();
const p = fetch(url, { signal: ctrl.signal });
ctrl.abort(); // p rejects with AbortError DOMException
Iemesls pēc noklusējuma ir AbortError, taču varat norādīt savu:
ctrl.abort(new Error('user cancelled'));
fetch noraida pieprasījumu ar jūsu norādīto vērtību.
Noildze
const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
AbortSignal.timeout(ms) atgriež signālu, kas pārtrauc darbību pēc ms. Taimeris darbojas, izmantojot dzinēja notikumu cilpu — to pašu, kas vada setTimeout / queueMicrotask (skatiet API: Notikumu cilpa). Fetch transports pārsūtīšanas laikā pārbauda signālu — noklusējuma CurlTransport gadījumā ar CURLOPT_PROGRESSFUNCTION — tāpēc pieprasījums tiek ātri pārtraukts, tiklīdz iestājas noildze.
Pēc noklusējuma cilpa darbojas virtuālajā laikā: tā pārbīda pulksteni uz nākamo gaidāmo termiņu, nevis guļ PHP, tāpēc fetch(url, { signal: AbortSignal.timeout(5000) }) vai nu tiek pabeigts pirms termiņa, vai tiek pārtraukts nākamajā cilpas solī — PHP nekad nav jāgaida. Lai darbotos reālā laikā, resursdatoram jāvada tickEventLoop(), izmantojot reāllaika pulksteni.
Sacensība: uzvar pirmā atcelšana
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
Izplatīšana pa slāņiem
Ietveriet savu asinhrono darbu ciklā, kas ņem vērā signālu:
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 pieprasījums tieši pārmanto signālu; manuālais if (signal.aborted) nosedz pārtraukumus starp pieprasījumiem, kad lapas cikls citādi turpinātu darboties.
Abort notikuma klausīšanās
ctrl.signal.addEventListener('abort', () => {
releaseDatabaseLock();
cancelDownstreamWork();
});
signal.reason tiek iestatīts, pirms tiek izsaukti klausītāji.
Signāls pielāgotā fetch transportā
Ja maināt transportu, izmantojot setFetchTransport(), signāls jūsu izsaucamajai funkcijai tiek nodots kā JsObject. Lai to ievērotu, regulāri pārbaudiet signālu:
$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',
);
}
// ...
});
Izmetot TransportException ar kind: 'aborted', JS pusē fetch tiek noraidīts ar AbortError DOMException — tāpat kā gadījumā, ja būtu darbojies specifikācijā noteiktais pārtraukšanas cikls.
Ja aizmugursistēmas atbalsta iebūvētu atcelšanu (Guzzle on_progress un Symfony ResponseInterface::cancel), pievienojiet tādu pašu pārbaudes un kļūdas izmešanas loģiku.
Paņēmieni, kas pagaidām nedarbojas
signal.addEventListener('abort', () => fetch(cleanupUrl))— klausītāji tiek izsaukti sinhroni; tīrīšanas fetch pieprasījums sākas, taču netiks pabeigts aborta izsaukšanas laikā. Ieplānojiet to, izmantojot apkārtējoawait.
setTimeout(() => ctrl.abort(), N) darbojas (taimeru saime ir pieejama un pārbaudīta ar WPT), taču AbortSignal.timeout(N) ir īsāks un skaidrāk izsaka nolūku, ja vajadzīgs tikai signāls, kas pārtrauc darbību pēc termiņa.
Skatiet arī
- Fetch transports — pilna pieprasījuma/atbildes/signāla saskarne pielāgotiem transportiem.
- Tīmekļa API (WPT) — AbortController/AbortSignal WPT sekmīgo testu īpatsvars.