Pāriet uz saturu

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

JavaScript
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:

JavaScript
ctrl.abort(new Error('user cancelled'));

fetch noraida pieprasījumu ar jūsu norādīto vērtību.

Noildze

JavaScript
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

JavaScript
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:

JavaScript
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

JavaScript
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:

PHP
$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ējo await.

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.