# Angular'da RxJS 2026: Operatörler, Subject'ler ve Signals Interop > Angular'da RxJS 2026: üretimde kullanılan operatörleri, Subject'leri ve Signals interop kalıplarını öğrenin, ayrıca en sık karşılaşılan mülakat sorularını. - Published: 2026-07-02 - Updated: 2026-07-07 - Author: SharpSkill - Tags: angular, rxjs, signals, observables, typescript, deep-dive - Reading time: 10 min --- RxJS, Angular'da 2026 yılında da asenkron programlamanın belkemiği olmayı sürdürüyor; Signals, Angular bileşenlerinin senkron durumu izleme biçimini yeniden şekillendirse bile. Ne zaman bir Observable'a başvurulacağını, ne zaman bir Signal'in daha uygun olduğunu ve ikisinin nasıl birlikte çalıştığını bilmek artık her Angular geliştiricisi için temel bir beceri. Bu derinlemesine inceleme, mülakatta kendinden emin bir yanıtı tıkanıp kalan bir yanıttan ayıran operatörleri, Subject'leri ve interop kalıplarını adım adım ele alıyor. > **Tek cümlede Signals ile Observables** > > Signals, her zaman güncel bir değere sahip olan senkron durumu modeller; Observables ise zaman içinde akan asenkron olay akışlarını modeller. Angular 20 her ikisini de korur ve `@angular/core/rxjs-interop` paketi ikisi arasındaki resmi köprüdür. ## Angular Signals'in yanında RxJS neden hâlâ önemli Signals'in tanıtılması birçok ekibi RxJS'in devrinin kapanıp kapanmadığını sormaya yöneltti. Üç ana sürüm sonrasında yanıt: hayır. Signals, şu anda bir değeri olan durumu temsil etmekte üstündür: bir sayaç, bir form alanı, seçili bir sekme. Observables ise zaman içinde gelen ve dönüştürme, iptal etme ya da birleştirme gerektirebilen olayları modellemekte üstündür: HTTP yanıtları, WebSocket mesajları, klavye girişi, router olayları ve zamanlayıcılar. Angular'ın kendi API'leri bu ayrımı görünür kılar. `HttpClient` hâlâ Observables döndürür. Reaktif formlar `valueChanges` ve `statusChanges`'i Observables olarak sunar. Router olayları bir Observable üzerinden akar. Aynı kanaldan birden fazla asenkron olayın aktığı her yerde RxJS operatörleri hâlâ mevcut en anlatımlı araçtır. Resmi [Angular reaktiflik kılavuzu](https://angular.dev/guide/signals/rxjs-interop) iki modeli rakip değil tamamlayıcı olarak ele alır ve [RxJS belgeleri](https://rxjs.dev/guide/overview) her önemsiz olmayan veri akışı için gerekli bir başvuru kaynağı olmayı sürdürür. Code review'da geçerliliğini koruyan pratik kural: şablonlarda okunan yerel bileşen durumu için Signals, operatör gerektiren asenkron ardışık düzenler için Observables kullanın. Interop katmanı ikisini birbirine bağlar, böylece hiçbir model bir duvara dönüşmez. Birleştirme operatörleri bu noktayı pekiştirir. Rota parametrelerini bir kullanıcının kaydettiği filtreler ve canlı bir fiyat akışıyla birleştirmek gibi birkaç asenkron kaynağı koordine etmek, tam olarak `combineLatest`, `withLatestFrom` ve `forkJoin`'in var olma amacıdır. Signals başka sinyallerden hesaplanmış değerler türetebilir, ancak "yalnızca her üç kaynak da en az bir değer ürettikten sonra yay" gibi zamana dayalı bir koordinasyonu ifade edemez. Zaman içinde bu bildirimsel bileşim, RxJS'in araç kutusunda kalmasının kalıcı nedenidir. ## Her Angular geliştiricisinin dayandığı temel RxJS operatörleri Operatörler, bir Observable alıp yenisini döndüren saf fonksiyonlardır. Klasik mülakat senaryosu yazarken aramadır, çünkü aynı anda dört operatörü çalıştırır: girişi kısıtlar, yinelenenleri atlar, eskimiş istekleri iptal eder ve hatalardan toparlanır. ```typescript // search.component.ts import { Component, inject } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { HttpClient } from '@angular/common/http'; import { debounceTime, distinctUntilChanged, switchMap, catchError } from 'rxjs/operators'; import { of } from 'rxjs'; @Component({ selector: 'app-search', imports: [ReactiveFormsModule], template: ``, }) export class SearchComponent { private http = inject(HttpClient); query = new FormControl(''); results$ = this.query.valueChanges.pipe( debounceTime(300), // wait until typing pauses for 300ms distinctUntilChanged(), // ignore emissions that repeat the last value switchMap((term) => // cancel the in-flight request, start a fresh one this.http.get(`/api/search?q=${term}`).pipe( catchError(() => of([])) // recover from a failed request without killing the stream ) ) ); } ``` Mülakatçıların irdelediği ince ayrıntı, `catchError` onun içine yerleştirilmişken neden `switchMap`'in dış düzeyde yer aldığıdır. `catchError`'ı iç HTTP Observable'ına koymak, başarısız bir isteğin boş bir dizi döndürmesi ve dış akışın akmayı sürdürmesi anlamına gelir. `catchError`'ı dış pipe'a taşımak, ilk hatadan sonra tüm aramayı sonlandırır ve sonraki her tuş vuruşunu bozar. Dört düzleştirme operatörünün her biri farklı bir eşzamanlılık sorusuna yanıt verir ve yanlışını seçmek Angular uygulamalarında yarış koşullarının en yaygın kaynaklarından biridir. > **Bir düzleştirme operatörü seçmek** > > Önceki iç isteği iptal edip yalnızca en sonuncuyu tutmak için `switchMap` kullanın (typeahead arama). Her iç isteği eşzamanlı çalıştırmak için `mergeMap` kullanın (bağımsız paralel yüklemeler). İstekleri kesin bir sırayla kuyruğa almak için `concatMap` kullanın (üst üste binmemesi gereken sıralı yazmalar). Geçerli olan bitene kadar yeni girişleri yok saymak için `exhaustMap` kullanın (çift tıklanan bir gönder düğmesini engellemek). Bu seçimi doğru yapmak, kararsız bir özelliği öngörülebilir bir özelliğe dönüştürür. [SharpSkill RxJS operatörleri modülü](/technologies/angular/interview-questions/rxjs-operators), her operatörün önlediği yarış koşullarını birebir yeniden üreten notlandırılmış sorularla bu ayrımları çalıştırır. ## Subject'ler ve multicasting: BehaviorSubject, ReplaySubject ve Subject Düz bir Observable unicast'tir: her abone taze bir yürütme tetikler. Bir Subject hem bir Observable hem de bir Observer'dır, bu da onu multicast yapar. Bu özellik, Subject'leri bir servis içinde hafif bir durum deposu ya da olay veri yolu kurmanın standart yolu hâline getirir. Üç varyant, geç abonelere neyi yeniden oynattıklarıyla ayrışır. Düz bir `Subject` geçmişten hiçbir şey yaymaz, bu yüzden bir abone yalnızca abone olduktan sonra gelen değerleri görür. Bir `BehaviorSubject` güncel değeri saklar ve onu hemen yeniden oynatır; başlangıç değerine ihtiyaç duymasının nedeni budur. Bir `ReplaySubject`, yapılandırılabilir sayıda geçmiş yayını arabelleğe alır ve hepsini yeniden oynatır. ```typescript // cart.service.ts import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class CartService { // BehaviorSubject holds the latest value and replays it to new subscribers private readonly itemsSubject = new BehaviorSubject([]); // expose a read-only stream, never the writable Subject itself readonly items$ = this.itemsSubject.asObservable(); add(item: string): void { const current = this.itemsSubject.value; // synchronous access to the last value this.itemsSubject.next([...current, item]); // emit the next immutable state } } ``` Burada iki alışkanlık önemlidir. İlki, Subject yerine `asObservable()` sunmak, dış kodun `next()` çağırıp durumu arka kapıdan değiştirmesini engeller. İkincisi, yerinde değiştirmek yerine yeni bir dizi referansı yaymak, değişiklik algılamayı ve eşitlik kontrollerini öngörülebilir tutar. Bu kalıp Signals'ten öncedir ve birbiriyle ilgisiz birçok bileşenin tükettiği paylaşımlı, enjekte edilebilir durum için hâlâ iyi çalışır. Bununla birlikte, yalnızca şablonlarda okunan tek bir güncel değeri tutmak için kullanılan bir `BehaviorSubject` artık çoğu zaman yazılabilir bir Signal olarak daha iyi ifade edilir; bu, aboneliği ve `asObservable()` seremonisini ortadan kaldırır. Depo aynı zamanda yayınlarını dönüştürmesi, kısıtlaması ya da başka akışlarla birleştirmesi gerektiğinde Subject daha güçlü seçim olmayı sürdürür, çünkü bu operatörlerin doğrudan bir Signal karşılığı yoktur. Her yerde birini varsayılan yapmak yerine kullanım durumuna göre ikisi arasında karar vermek, mülakatçıların ödüllendirdiği bir akıcılık işaretidir. ## toSignal ve toObservable ile RxJS signals interop Interop paketi iki başrol fonksiyonuyla gelir. `toSignal`, bir Observable'ı bir şablonun doğrudan tüketebileceği salt okunur bir Signal'e dönüştürür ve abonelik yaşam döngüsünü otomatik yönetir. `toObservable` bunun tersini yapar; bir Signal'i bir Observable'a çevirerek RxJS operatörlerinin onun değişikliklerini işleyebilmesini sağlar. ```typescript // dashboard.component.ts import { Component, signal, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { toSignal, toObservable } from '@angular/core/rxjs-interop'; import { switchMap } from 'rxjs/operators'; @Component({ selector: 'app-dashboard', template: `{{ user()?.name }}` }) export class DashboardComponent { private http = inject(HttpClient); // a Signal drives the query; toObservable turns each change into a stream event readonly userId = signal(1); private readonly user$ = toObservable(this.userId).pipe( switchMap((id) => this.http.get<{ name: string }>(`/api/users/${id}`)) ); // toSignal subscribes immediately and unsubscribes on destroy, no manual teardown readonly user = toSignal(this.user$, { initialValue: null }); } ``` `initialValue` seçeneği dikkati hak eder. O olmadan `toSignal`, henüz hiçbir şey yayılmadığı için değer ya da `undefined` olarak tiplenmiş bir Signal döndürür. `initialValue: null` geçmek, şablona tanımlı bir başlangıç durumu ve daha temiz bir tip verir. Bir `BehaviorSubject` gibi senkron kaynaklar için `requireSync: true`, ilk okumada bir değerin hazır olmasını garanti eder ve `undefined`'ı tipten tümüyle çıkarır. Bu iki yönlü köprü, bir kod tabanının mevcut her Observable ardışık düzenini yeniden yazmadan Signals'i kademeli olarak benimsemesini sağlar. Beraberindeki [Angular Signals mülakat modülü](/technologies/angular/interview-questions/angular-signals) reaktiflik modelini derinlemesine ele alır ve [Angular 18 Signals özelliklerine genel bakış](/blog/angular/angular-18-signals-new-features) bu ilkellerin nasıl evrildiğini izler. ## rxResource ile Observable'ları signal kaynaklarına köprülemek Angular 20, bir Observable'dan asenkron veriyi signal tabanlı duruma yüklemenin bildirimsel yolu olarak `rxResource`'u öne çıkarır. Yükleme, hata ve çözülmüş durumu signals olarak izler; bu da HTTP çağrılarının eskiden gerektirdiği manuel abonelik defter tutmanın çoğunu ortadan kaldırır. ```typescript // products.component.ts import { Component, signal, inject } from '@angular/core'; import { rxResource } from '@angular/core/rxjs-interop'; import { HttpClient } from '@angular/common/http'; @Component({ selector: 'app-products', template: `` }) export class ProductsComponent { private http = inject(HttpClient); readonly category = signal('laptops'); // Angular 20 renamed the fields: request -> params and loader -> stream readonly products = rxResource({ params: () => ({ category: this.category() }), stream: ({ params }) => this.http.get(`/api/products?category=${params.category}`), }); // products.value(), products.isLoading() and products.error() are all signals } ``` Angular 19'daki `request`/`loader`'dan Angular 20'deki `params`/`stream`'e yeniden adlandırma sık bir tökezleme noktasıdır, bu yüzden güncel alan adlarını anmak bir mülakatta güncel bilgiye işaret eder. `category` signal'i değiştiğinde `rxResource` önceki isteği iptal eder ve yeni bir akış başlatır; bu da `switchMap` semantiğini bedavaya verir. [rxResource API başvurusu](https://v20.angular.dev/api/core/rxjs-interop/rxResource) tam durum yaşam döngüsünü belgeler. ## takeUntilDestroyed ile bellek sızıntılarından kaçınmak Bileşeninden daha uzun yaşayan her manuel `subscribe()`, bellek sızdırır ve yok edilmiş bir görünüme karşı geri çağrıları tetikleyebilir. Tarihsel çözüm, `ngOnDestroy`'da tamamlanan bir Subject ile `takeUntil(this.destroy$)` kalıbıydı. Angular bu tekrar eden şablonu, aboneliği geçerli enjeksiyon bağlamına ya da açık bir `DestroyRef`'e bağlayan `takeUntilDestroyed` operatörüyle değiştirdi. ```typescript // live-feed.component.ts import { Component, inject, DestroyRef } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { interval } from 'rxjs'; @Component({ selector: 'app-live-feed', template: `` }) export class LiveFeedComponent { private destroyRef = inject(DestroyRef); constructor() { interval(1000) // completes the subscription automatically when the component is destroyed .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((tick) => console.log('tick', tick)); } } ``` Bir kurucu ya da alan başlatıcısı içinde çağrıldığında `takeUntilDestroyed()`, ortamdaki `DestroyRef`'i okuduğu için argümana gerek duymaz. Başka bir yerde, örneğin bir metot içinde çağrıldığında, yukarıda gösterildiği gibi açıkça geçirilen bir `DestroyRef` gerektirir. `toSignal` ve `rxResource`'u tercih etmek manuel abonelikleri tümüyle ortadan kaldırır; bu, sızıntılardan kaçınmanın en temiz yoludur. Ham bir aboneliğe gerçekten ihtiyaç duyulduğunda `takeUntilDestroyed` doğru korumadır. > **Enjeksiyon bağlamı tuzağı** > > `takeUntilDestroyed()`'ı bir enjeksiyon bağlamının dışında argümansız çağırmak bir çalışma zamanı hatası fırlatır. Bir olay işleyicisi, bir `setTimeout` ya da bir RxJS geri çağrısı içinde abone olmak bu bağlamın dışındadır, bu yüzden `DestroyRef` daha önce (genellikle enjekte edilmiş bir alan olarak) yakalanıp açıkça geçirilmelidir. Bunu unutmak, "takeUntilDestroyed() can only be used within an injection context" hatasının en sık nedenidir. ## Tekrar edilmeye değer Angular RxJS mülakat soruları Mülakatçılar genellikle aynı yüksek sinyalli konuların etrafında döner. Bunları net biçimde yanıtlayabilmek, RxJS'i kullanmış adayları yalnızca onun hakkında okumuş olanlardan ayırır. - **Hot ve cold Observables.** Cold Observable üreticisini her abonelikte başlatır, bu yüzden her abone bağımsız bir yürütme alır (taze bir HTTP isteği). Hot Observable tek bir üreticiyi aboneler arasında paylaşır; Subject'ler ve `share()`'in yarattığı şey budur. - **switchMap, mergeMap, concatMap ve exhaustMap.** `switchMap` önceki iç Observable'ı iptal eder (arama için ideal). `mergeMap` tüm iç Observable'ları eşzamanlı çalıştırır. `concatMap` onları sırayla kuyruğa alır. `exhaustMap` biri çalışırken yeni girişleri yok sayar (çift form gönderimini önlemek için ideal). - **Bellek sızıntıları nasıl önlenir.** Tümü otomatik abonelikten çıkan `toSignal`, `rxResource` ya da `async` pipe'ı tercih edin; manuel abonelikler için `takeUntilDestroyed` kullanın. - **Bir Observable ne zaman Signal'e dönüştürülür.** Bir şablonun bir değere senkron ihtiyaç duyduğu ve kaynağın asenkron olduğu durumlarda `toSignal`'a başvurun; böylece değişiklik algılama en son değeri bir `async` pipe olmadan okur. Bunların notlandırılmış sürümlerini zaman baskısı altında çalışmak, onları içselleştirmenin en hızlı yoludur. [Angular teknoloji merkezi](/technologies/angular) bu sorulara doğrudan karşılık gelen RxJS, Signals ve değişiklik algılama modüllerini bir araya getirir. ## Sonuç RxJS ve Signals modern Angular yığınında rakip değil, ortaktır. Bir sonraki projeye ya da mülakata taşımaya değer çıkarımlar: - Senkron bileşen durumu için Signals, operatör gerektiren asenkron olay ardışık düzenleri için Observables kullanın. - Eskimiş işi iptal etmek için `switchMap`'e, yinelenenleri engellemek için `exhaustMap`'e başvurun ve dış akışın hataları atlatması için `catchError`'ı iç Observable'da tutun. - Subject durumunu `asObservable()` üzerinden sunun ve değişiklik algılamayı öngörülebilir tutmak için değişmez değerler yayın. - İki modeli `toSignal` ve `toObservable` ile köprüleyin ve temiz tipler için `initialValue` ya da `requireSync` geçirin. - Angular 20'de asenkron veriyi `rxResource` ile bildirimsel olarak yükleyin ve `params` ile `stream` alan adlarını unutmayın. - Sızıntıları ortadan kaldırmak için kalan her manuel aboneliği `takeUntilDestroyed` ile koruyun. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/angular/rxjs-angular-operators-subjects-signals-interop