
# AbortController kullanım örüntüleri

`AbortController` ve `AbortSignal`, Phasis içinde WHATWG standartlarının tümünü uygular. Standart bileşim yardımcıları (`AbortSignal.any`, `AbortSignal.timeout`) da sunulur. Bu sayfa, sık kullanılan örüntüleri ve iptalin PHP sınırı boyunca nasıl yayıldığını açıklar.

## Bir fetch isteğini iptal etme

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

Varsayılan neden `AbortError`'dır; ancak kendi nedeninizi sağlayabilirsiniz:

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

`fetch`, geçirdiğiniz değerle reddedilir.

## Zaman aşımı

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

`AbortSignal.timeout(ms)`, `ms` sonra kendini iptal eden bir sinyal döndürür. Zamanlayıcı, `setTimeout` / `queueMicrotask` işlevlerini çalıştıranla aynı olan motorun olay döngüsü üzerinden tetiklenir (bkz. [API: Olay döngüsü](https://phasis.inline0.dev/tr/docs/api#event-loop)). Fetch aktarımı, aktarım sırasında sinyali yoklar; varsayılan `CurlTransport` için `CURLOPT_PROGRESSFUNCTION` aracılığıyla. Böylece süre dolduğunda istek hızla iptal edilir.

Döngü varsayılan olarak **sanal zamanlıdır**: uyumak PHP yerine saatini bekleyen bir sonraki son tarihe ilerletir; böylece `fetch(url, { signal: AbortSignal.timeout(5000) })` ya son tarihten önce tamamlanır ya da sonraki döngü adımında iptal edilir — PHP'ın beklemesine asla neden olmaz. Gerçek zamanlı ilerleme için ana makinenin `tickEventLoop()` işlevini gerçek saate göre çalıştırması gerekir.

## Yarış: ilk iptal kazanır

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

## Katmanlar boyunca yayılım

Kendi eşzamansız işinizi sinyali izleyen bir döngüyle sarın:

```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 sinyali doğrudan devralır; manuel `if (signal.aborted)` ise istekler arasındaki boşlukları kapsar; aksi hâlde sayfa döngüsü çalışmaya devam eder.

## İptal olayını dinleme

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

Dinleyiciler çalıştırılmadan önce `signal.reason` ayarlanır.

## Özel bir fetch aktarımında sinyal

Aktarımı `setFetchTransport()` aracılığıyla değiştirirseniz sinyal, çağrılabilir işlevinize `JsObject` olarak iletilir. Sinyali periyodik olarak kontrol ederek dikkate alın:

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

`kind: 'aborted'` ile `TransportException` fırlatmak, JS tarafındaki `fetch`'ın `AbortError DOMException` ile reddedilmesini sağlar — spesifikasyondaki iptal döngüsü çalışmış gibi.

Yerel iptal desteği olan arka uçlarda (Guzzle için `on_progress`, Symfony için `ResponseInterface::cancel`), aynı kontrol edip hata fırlatma düzenini bağlayın.

## Henüz çalışmayan kalıplar

- **`signal.addEventListener('abort', () => fetch(cleanupUrl))`** — dinleyici eşzamanlı çalışır; temizlik fetch'i başlar ancak iptal olayı işlenirken tamamlanmaz. Bunu çevresindeki `await` üzerinden zamanlayın.

`setTimeout(() => ctrl.abort(), N)` çalışır (zamanlayıcı ailesi sunulur ve WPT kapsamındadır), ancak tek istediğiniz son tarihten sonra iptal sinyali vermekse `AbortSignal.timeout(N)` daha kısadır ve amacı daha iyi anlatır.

## Ayrıca bkz.

- [Fetch aktarımı](https://phasis.inline0.dev/tr/docs/interop/fetch-transport) — özel aktarımlar için tam istek/yanıt/sinyal arayüzü.
- [Web API'leri (WPT)](https://phasis.inline0.dev/tr/docs/compatibility/web-apis) — AbortController/AbortSignal WPT geçme oranı.
