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
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:
ctrl.abort(new Error('user cancelled'));
fetch, geçirdiğiniz değerle reddedilir.
Zaman aşımı
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
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:
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
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:
$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 çevresindekiawaitü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ı — özel aktarımlar için tam istek/yanıt/sinyal arayüzü.
- Web API'leri (WPT) — AbortController/AbortSignal WPT geçme oranı.