
# Vzorci za AbortController

`AbortController` in `AbortSignal` sta popolni implementaciji WHATWG v Phasis. Na voljo sta tudi standardna pomočnika za sestavljanje (`AbortSignal.any`, `AbortSignal.timeout`). Ta stran obravnava najpogostejše vzorce in širjenje preklica čez mejo PHP.

## Preklic zahteve fetch

```js
const ctrl = new AbortController();
const p = fetch(url, { signal: ctrl.signal });
ctrl.abort();                     // p rejects with AbortError DOMException
```

Razlog je privzeto `AbortError`, lahko pa navedete svojega:

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

`fetch` zavrne z vrednostjo, ki ste jo podali.

## Časovna omejitev

```js
const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
```

`AbortSignal.timeout(ms)` vrne signal, ki se sam prekine po `ms`. Časovnik se sproži prek zankovnega izvajanja dogodkov pogona, istega, ki poganja `setTimeout` / `queueMicrotask` (glejte [API: Zanka dogodkov](https://phasis.inline0.dev/sl/docs/api#event-loop)). Prenosni mehanizem za pridobivanje podatkov med prenosom preverja signal — pri privzetem `CurlTransport` prek `CURLOPT_PROGRESSFUNCTION` — zato se zahteva prekine takoj, ko poteče rok.

Zanka je privzeto v **navideznem času**: uro pomakne na naslednji čakajoči rok, namesto da bi spala PHP, zato se `fetch(url, { signal: AbortSignal.timeout(5000) })` bodisi zaključi pred rokom bodisi prekine ob naslednjem koraku zanke — PHP nikoli ne pusti čakati. Za izvajanje v realnem času mora gostitelj poganjati `tickEventLoop()` glede na stensko uro.

## Dirka: prvo preklicanje zmaga

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

## Razširjanje skozi plasti

Zanko, ki upošteva signal, uporabite za ovijanje lastnega asinhronega dela:

```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;
}
```

Pridobivanje neposredno podeduje signal; ročni `if (signal.aborted)` pokrije vrzeli med zahtevami, ko bi se sicer zanka strani še naprej izvajala.

## Poslušanje dogodka prekinitve

```js
ctrl.signal.addEventListener('abort', () => {
  releaseDatabaseLock();
  cancelDownstreamWork();
});
```

`signal.reason` je nastavljen, preden se sprožijo poslušalci.

## Signal v prenosu fetch po meri

Če zamenjate prenos prek `setFetchTransport()`, je signal vaši klicni funkciji posredovan kot `JsObject`. Upoštevajte ga s preverjanjem:

```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',
        );
    }
    // ...
});
```

Če sprožite `TransportException` z `kind: 'aborted'`, bo JS-stranski `fetch` zavrnjen z `AbortError DOMException` — enako, kot če bi se izvedla zanka za prekinitev iz specifikacije.

Pri zalednih sistemih z vgrajenim preklicem (Guzzle: `on_progress`, Symfony: `ResponseInterface::cancel`) uporabite enak vzorec preverjanja in sprožitve napake.

## Vzorci, ki še ne delujejo

- **`signal.addEventListener('abort', () => fetch(cleanupUrl))`** — poslušalci se sprožijo sinhrono; čiščenje začne zahtevo fetch, vendar se ta ne zaključi med pošiljanjem dogodka prekinitve. Načrtujte jo prek okoliškega `await`.

`setTimeout(() => ctrl.abort(), N)` deluje (družina časovnikov je vključena in pokrita s testi WPT), vendar je `AbortSignal.timeout(N)` krajši in bolje izraža namen, kadar želite le signal za prekinitev po preteku roka.

## Glejte tudi

- [Prenos Fetch](https://phasis.inline0.dev/sl/docs/interop/fetch-transport) — celoten vmesnik zahtev/odgovorov/signalov za prenose po meri.
- [Spletni API-ji (WPT)](https://phasis.inline0.dev/sl/docs/compatibility/web-apis) — uspešnost testov WPT za AbortController/AbortSignal.
