Web programlama eğitimi kapsamında, arama ve filtre ekranlarında eski HTTP yanıtlarının yeni state'i ezmesini AbortController, sıra numarası ve framework yaşam döngüsüyle engellemeyi inceliyoruz.
Web Programlama Eğitimi: AbortController ile Eski İstekleri Kesmek
Web Programlama Eğitimi: Yarış koşulunun gerçek nedeni
Bir arama kutusunda kullanıcı "rea", sonra "react" yazdığında ikinci istek sunucuya daha sonra ulaşsa bile ilk yanıtın önce veya sonra dönmesi garanti değildir. Sorun yalnızca ağ gecikmesi değildir: istemci tarafında JSON ayrıştırma, cache katmanı ve state güncelleme kuyruğu da farklı zamanlarda tamamlanır. Chrome DevTools Network panelinde "Disable cache" açıkken iki sorguyu tetikleyin; Initiator ve Waterfall sütunlarıyla eski yanıtın sonradan geldiğini doğrulayın. Bu senaryo, web programlama eğitimi içinde özellikle arama, typeahead, ürün filtresi ve canlı doğrulama bileşenlerinde test edilmelidir.
Sadece AbortController kullanmak her zaman yeterli değildir. abort() çağrısı fetch'in bekleyen promise'ını AbortError ile reddeder ve Response.body tüketimini durdurur; ancak istek sunucuya ulaştıysa sunucudaki sorgu çalışmayı sürdürebilir. Dahası, abort kontrolü JSON parse işleminden sonra yapılıyorsa önceden tamamlanmış bir yanıt state'i ezebilir. Bu nedenle istemci kodunda hem iptal sinyali hem de monoton artan bir istek kimliği kullanın.
Fetch katmanında AbortSignal ve sıra numarası tasarımı
Aşağıdaki sınıf her yeni aramada önceki controller'ı iptal eder ve yanıtı yazmadan önce sequence değerini doğrular. sequence denetimi, önceki fetch yanıtı abort edilmeden hemen önce resolve olmuşsa oluşabilecek dar zaman penceresini kapatır. API istemcinizde signal parametresini isteğe bağlı değil zorunlu yapmak, alt katmanların iptal bilgisini kaybetmesini önler.
class LatestSearch {
#controller = null;
#sequence = 0;
async run(query) {
this.#controller?.abort();
this.#controller = new AbortController();
const sequence = ++this.#sequence;
try {
const response = await fetch(
`/api/search?q=${encodeURIComponent(query)}`,
{ signal: this.#controller.signal, headers: { Accept: "application/json" } }
);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
if (sequence !== this.#sequence) return { stale: true, data: null };
return { stale: false, data };
} catch (error) {
if (error.name === "AbortError") return { stale: true, data: null };
throw error;
}
}
}Yaygın hata, AbortError'u uygulamanın hata izleme sistemine gerçek hata gibi göndermektir. Sentry veya OpenTelemetry span durumunu `UNSET` bırakmak ya da iptal olayını ayrı bir sayaçta tutmak daha anlamlıdır. Bunun karşılığında 500, DNS ve JSON parse hatalarını gizlemeyin. Ayrıca `Promise.all()` ile aynı signal altında paralel istek çalıştırırsanız tek bir abort tüm üyeleri iptal eder; bağımsız hata toleransı istiyorsanız her kaynak için ayrı controller oluşturun.
ReactJS eğitimi, VueJS eğitimi ve Angular eğitimi için yaşam döngüsü
Bir reactjs eğitimi örneğinde controller'ı render sırasında değil `useEffect` içinde oluşturun. Render aşaması React'in geliştirme denetimlerinde tekrar çalışabilir ve henüz ekrana bağlanmamış bir render için ağ isteği başlatmak yan etkidir. Cleanup fonksiyonu bileşen unmount olduğunda veya query değiştiğinde isteği keser; `setResult` öncesindeki `signal.aborted` kontrolü ise parse sonrası güncellemeyi engeller.
import { useEffect, useState } from "react";
export function Search({ query }) {
const [result, setResult] = useState([]);
useEffect(() => {
if (query.length < 2) {
setResult([]);
return;
}
const controller = new AbortController();
(async () => {
try {
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`, {
signal: controller.signal
});
const json = await res.json();
if (!controller.signal.aborted) setResult(json.items);
} catch (e) {
if (e.name !== "AbortError") throw e;
}
})();
return () => controller.abort();
}, [query]);
return <SearchResults items={result} />;
}VueJS eğitimi için aynı yaşam döngüsü `watch(query, async (_, __, onCleanup) => { ... })` içindeki `onCleanup(() => controller.abort())` ile kurulabilir. Angular eğitimi tarafında HttpClient akışına `switchMap` uygulayın: yeni query emisyonu geldiğinde önceki inner Observable unsubscribe edilir. Örneğin `query$.pipe(debounceTime(150), distinctUntilChanged(), switchMap(q => this.http.get('/api/search', { params: { q } })))` zincirinde `mergeMap` kullanmak eski yanıtların UI'a yazılmasına izin verir. 150 ms debounce ölçülmesi gereken bir başlangıç değeridir; mobil klavye ve API p95 süresine göre ayarlanmalıdır.
Frontend framework karşılaştırması: iptal semantiği ve eski istemciler
Frontend framework karşılaştırması yaparken yalnızca render maliyetini değil, kaynak temizleme modelini de değerlendirin. React'te effect cleanup, Vue'da watcher cleanup, Angular'da `switchMap` unsubscribe mekanizması iptal noktasını tanımlar. Ancak Angular HttpClient isteğinin ağda iptal edilmesi kullanılan backend'e bağlıdır; uygulama kodu yine de abonelikten sonra gelen değeri state'e yazmayacak şekilde akışı kurmalıdır. RxJS tarafında `takeUntilDestroyed()` eklemek, bileşen yok edildiğinde uzun yaşayan stream'lerin aboneliğini sonlandırır.
AngularJS eğitimi sürdüren ekiplerde `$http` için AbortController doğrudan standart entegrasyon olmayabilir. Eski `$http` arayüzünde `timeout` alanına resolve edilebilen bir `$q.defer()` promise'i vererek isteği iptal edin. Controller oluşturup her tuş vuruşunda yenilemek yerine, servis katmanında önceki deferred nesnesini resolve edin ve yanıtı requestId ile doğrulayın. Bu ayrıntı önemlidir: yalnızca timeout resolve etmek, zaten tamamlanmış callback'in scope state'ini yazmasını engellemez.
React Native eğitimi için de fetch çağrılarına signal geçirin, fakat hedeflediğiniz çalışma zamanında AbortController desteğini cihaz matrisiyle test edin. Uygulamanın minimum çalışma zamanı bunu sağlamıyorsa, rastgele bir polyfill eklemek yerine HTTP istemcinizin iptal API'sini ve native köprü davranışını doğrulayın. Özellikle ekran geri navigasyonunda controller cleanup'ı yapılmazsa görünmeyen ekranın sonucu global store'a yazması mümkündür.
JavaScript eğitimi kapsamında iptali ölçmek ve regresyonu yakalamak
JavaScript eğitimi laboratuvarında önce-sonra karşılaştırmasını aynı ağ koşulunda yapın. Chrome DevTools Network panelinden Fast 3G benzetimini seçin, arama alanına 10 karakterlik bir metni hızlıca yazın ve tamamlanan `/api/search` istek sayısını kaydedin. Değişiklik öncesinde her input olayı bir istek üretiyorsa 10 istek gözlenir; 150 ms debounce ve iptal sonrasında hedef, yalnızca duraklamalardan sonra gerekli isteklerin tamamlanmasıdır. Sunucu tarafında Nginx access log veya uygulama metriği ile istek sayısını ayrıca karşılaştırın; tarayıcıdaki "canceled" etiketi, sunucunun sorguyu hiç başlatmadığını kanıtlamaz.
Kullanıcı algısını ölçmek için son geçerli sonucun ekrana yazılma süresini Performance API ile işaretleyin. `performance.measure` kayıtlarını Chrome Performance panelinde veya `PerformanceObserver` ile telemetry hattında toplayın. İptal eklemek, her zaman p95 ağ süresini düşürmez; doğrulanabilir kazanım eski sonucun render edilmemesi ve gereksiz JSON parse işinin azalmasıdır.
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntriesByName("search-visible")) {
navigator.sendBeacon("/rum", JSON.stringify({
metric: entry.name,
duration: entry.duration
}));
}
});
observer.observe({ type: "measure", buffered: true });
async function searchAndRender(query, signal) {
performance.mark("search-start");
const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`, { signal });
const result = await response.json();
if (signal.aborted) return;
renderResults(result);
performance.mark("search-visible");
performance.measure("search-visible", "search-start", "search-visible");
}Bu ölçümde `search-start` ve `search-visible` adlarını eşzamanlı aramalar arasında benzersiz yapın, örneğin requestId ekleyin. Aksi halde iç içe çalışan ölçümler yanlış eşleşebilir veya DOMException üretebilir. CI tarafında Playwright ile gecikmeli yanıt senaryosu kurun: ilk route'u 800 ms, ikincisini 50 ms geciktirin ve ekranda yalnızca ikinci sorgunun görünür olduğunu assert edin.
İlgili Eğitim
YTÜSEM İlgili Eğitim
Angular İle Web Uygulama Geliştirme (en yakın eşleşen) (Yıldız Teknik Üniversitesi SEM)
Sık Sorulan Sorular
Web programlama eğitimi içinde fetch AbortController ne zaman kullanılmalı?
Kullanıcının yeni girdisinin eski sonucu anlamsız yaptığı arama, filtre, autocomplete ve ekran geçişi isteklerinde kullanın. Her isteğe `signal` geçin, cleanup içinde `abort()` çağırın ve state yazımından önce requestId veya `signal.aborted` kontrolü ekleyin.
ReactJS eğitimi için useEffect cleanup eski API yanıtını kesin engeller mi?
Cleanup bekleyen fetch'i iptal eder, fakat yanıt cleanup öncesinde resolve olmuş ve JSON parse başlamış olabilir. Bu nedenle `await response.json()` sonrasında `controller.signal.aborted` kontrolü yapın veya ref üzerinde artan requestId ile en son isteği doğrulayın.
Angular eğitimi projelerinde switchMap mi mergeMap mi kullanılmalı?
Arama gibi yalnızca en son değerin anlamlı olduğu akışta `switchMap` kullanın; yeni emisyon önceki inner Observable aboneliğini kapatır. Birden fazla bağımsız yazma işleminin tamamlanması gerekiyorsa `mergeMap` uygundur, ancak sonuçları request sırasına göre state'e yazmak için ek kimlik denetimi gerekir.
Frontend framework karşılaştırması yaparken AngularJS uygulamalarında istek iptali nasıl test edilir?
Protractor yerine güncel E2E aracınızla veya birim testte `$httpBackend` ile iki yanıtı ters sırada flush edin. `$q.defer()` timeout promise'ini resolve ettikten sonra eski callback'in `$scope.results` değerini değiştirmediğini requestId assert'i ile doğrulayın.
AI / LLM Discovery
Bu makale Opendart Akademi Web Programlama eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.


