Native Observables are now available in Chrome 135, offering deep integration into the Web API with .when()
methods and default multicasting behavior. Careful: They differ a little bit from RxJS Observables in structure and behavior (e.g., Promise-returning methods, AbortController for cancellation).
Native Observables
Native Observables have landed in Chrome 135 — but don’t confuse them with the RxJS Observables we’re used to. Before diving into the differences, let’s first look at how they’re integrated into the existing Web APIs.
Traditionally, we use addEventListener()
to register callbacks on DOM elements. With native Observables, these same elements now expose a when()
method that returns an Observable — a sign of how deeply integrated this feature is.
// until now
document.addEventListener('mousemove', console.log);
// with native Observables
document.when('mousemove').subscribe(console.log);
Key Differences from RxJS Observables
1. Multicasting Behavior by Default
Native Observables are shared by default. That means they’re multicasting, only activate on the first subscriber, and do not replay past values. This is similar to RxJS's share()
operator — but importantly, not shareReplay()
.
Given the following code in RxJS:
const numbers$ = new Observable((subscriber) => {
subscriber.next(1);
subscriber.next(2);
setTimeout(() => {
subscriber.next(3);
});
});
numbers$.subscribe((n) => console.log(`Sub 1: ${n}`));
numbers$.subscribe((n) => console.log(`Sub 2: ${n}`));
We would get the following output:
Sub 1: 1
Sub 1: 2
Sub 2: 1
Sub 2: 2
Sub 1: 3
Sub 2: 3
With native Observables, though, the same code would produce the following output:
Sub 1: 1
Sub 1: 2
Sub 1: 3
Sub 2: 3
That is because the first subscription triggers the execution within the Observable and numbers 1 and 2 are emitted synchronously. Only value 3 emits in an asynchronous task and is therefore also consumed by the second subscriber.
2. Operators as Methods
Instead of using pipe()
like in modern RxJS, native Observables go back to the roots: operators like map()
or filter()
are methods directly on the Observable instance.
This would be the RxJS-valid code:
// RxJS Observables
const numbers$ = new Observable<number>((subscriber) => {
subscriber.next(2);
subscriber.next(4);
subscriber.next(8);
});
numbers$
.pipe(
map((n) => n * 2),
tap((n) => console.log(`tap: ${n}`)),
filter((n) => n < 10),
)
.subscribe(console.log);
The same code but with native Observables:
// Native Observables
const numbers$ = new Observable((subscriber) => {
subscriber.next(2);
subscriber.next(4);
subscriber.next(8);
});
numbers$
.map((n) => n * 2)
.inspect((n) => console.log(`tap: ${n}`)) // <-- that's tap()
.filter((n) => n < 10)
.subscribe(console.log);
3. Promise-returning Methods
Some operators (like first()
, last()
, reduce()
, and forEach()
) return Promises, not Observables. They would also replace the necessity for an explicit subscribe
.
This makes them easier to use in async/await flows.
In RxJS, there are utility functions to map an Observable into a Promise:
// RxJS
const countdown = new Observable((subscriber) => {
let counter = 1;
const intervalId = setInterval(() => {
subscriber.next(counter++);
if (counter > 5) {
clearInterval(intervalId);
subscriber.complete();
}
});
});
await lastValueFrom(countdown.pipe(tap(console.log)));
console.log('ended');
With native Observables, last()
returns already the Promise instead an Observable.
// Native Observables
const countdown = new Observable((subscriber) => {
let counter = 1;
const intervalId = setInterval(() => {
subscriber.next(counter++);
if (counter > 5) {
clearInterval(intervalId);
subscriber.complete();
}
});
});
await countdown.inspect(console.log).last();
console.log("ended");
4. AbortController
instead unsubscribe()
Unsubscribing is handled via AbortController
, similar to how we cancel fetch()
requests. Angular’s new resource()
function uses this same pattern as well, so this approach should already feel familiar.
In RxJS, we usually use unsubscribe
, when the subscription does not want to receive values anymore.
// RxJS
const numbers$ = new Observable<number>((subscriber) => {
subscriber.next(1);
subscriber.next(2);
});
const subscription = numbers$.subscribe((value) => {
console.log(value);
if (value >= 1) {
console.log('aborting/unsubscribing (even synchronously)');
}
});
subscription.unsubscribe();
Since native Observables are much more integrated into the Web API, the unsubscription is done with the AbortController
:
// Native Observables
const numbers$ = new Observable((subscriber) => {
subscriber.next(1);
subscriber.next(2);
});
const abortController = new AbortController();
numbers$.subscribe(
(value) => {
console.log(value);
if (value >= 1) {
console.log("aborting/unsubscribing (even synchronously)");
abortController.abort(); // <-- "unsubscribe" here
}
},
{ signal: abortController.signal },
);
5. Teardown via addTeardown()
The constructor function of an Observable no longer returns a teardown function. Instead, teardown logic is registered using addTeardown()
.
RxJS Version:
// RxJS Observable
const numbers$ = new Observable<number>((subscriber) => {
subscriber.next(1);
subscriber.next(2);
return () => console.log('complete inside the observable');
});
With native Observables, the teardown function will be more obvious:
// Native Observables
const numbers$ = new Observable((subscriber) => {
subscriber.addTeardown(() => {
console.log("completes inside the observable");
subscriber.complete();
});
subscriber.next(1);
subscriber.next(2);
});
Will Observables Become a Language-Level Feature?
It’s still uncertain whether Observable will become a language-level standard (like Promise) — or if it will remain a browser-level Web API. That distinction will shape how deeply integrated they become across platforms.
https://github.com/wicg/observable?tab=readme-ov-file#standards-venue
What About RxJS?
RxJS 8 development had paused while waiting for native Observable readiness. Now that they’ve landed, RxJS will move forward with integrating them — including shims for environments where they aren’t available yet.
https://github.com/ReactiveX/rxjs/issues/6367
And Angular Signals?
No change there. Signals are for state, while Observables are for events — like DOM events or async completions. Observables can still be useful to model these event triggers, but state management in Angular is moving to Signals, not back to BehaviorSubject.
To experiment with the examples, fine a ready to use starter at https://stackblitz.com/edit/stackblitz-starters-ybgwzhbc
Framework Waves
At the dotJS conference, Sarah Drasner gave a talk on how modern frontend frameworks have been continuously influencing one another.
She pointed out, for instance, that Qwik’s approach to resumability was likely inspired by Wiz — Google’s internal framework that is now being integrated into Angular.
Naturally, she focused on Angular’s current role in this evolving landscape. With features like incremental hydration, Angular is now in a position to influence other frameworks in return.
She concluded her talk by mentioning a new open-source library called tsurge, which she suggested could complement Angular’s ng update capabilities.
NgRx 19.1
NgRx 19.1 was released. It comes with a new features for the SignalStore in the areas of
- Testing
- Custom Features
withEntities
https://github.com/ngrx/platform/blob/main/CHANGELOG.md#1910-2025-04-01
Top comments (4)
Why do you keep mentioning RxJS? I don't know
RxJS
and I don't care.What do you want to say? This is an article on Angular and you know that RxJS is heavily used in Angular.
I don't know Angular at all, so I also do not now RxJS at all, what is it and where is it used.
I clicked to read this article because header shows "native observables" with Chrome logo, so I wanted to learn what does this mean. not to get a whole lecture about angular and RxJS.
What I am saying this article header banner mislead me. I will filter out everything angular-related from now on
I see. It is little bit more complicated.
So RxJS used to be a library when it came to Reactive Programming in JavaScript. Rx means Reactive.
In RxJS, the basic type is the Observable and - generally speaking - it allows you to manage events. Angular has been using RxJS for more than 10 years now. So, when you are curious how RxJS can be used in an application, Angular might be good to check out some use cases.
Meanwhile, that Observable type from RxJS should be come standardized and Chrome did the first step integrating it natively.
This article is about the differences between RxJS and Observables. You don't need to know or use Angular in order to run the examples.
But since Ng-News is Angular News (ng is typically the synoym to Angular), there is also some Angular-related stuff at the end.