
# 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

```js
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:

```js
ctrl.abort(new Error('user cancelled'));
```

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

## Noildze

```js
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](https://phasis.inline0.dev/lv/docs/api#event-loop)). 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

```js
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:

```js
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

```js
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](https://phasis.inline0.dev/lv/docs/interop/fetch-transport) — pilna pieprasījuma/atbildes/signāla saskarne pielāgotiem transportiem.
- [Tīmekļa API (WPT)](https://phasis.inline0.dev/lv/docs/compatibility/web-apis) — AbortController/AbortSignal WPT sekmīgo testu īpatsvars.
