İçeriğe geç

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

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

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

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

Zaman aşımı

JavaScript
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ü). 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

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

Katmanlar boyunca yayılım

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

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

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