Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions apps/rxjs.dev/content/guide/observable.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Observables are lazy Push collections of multiple values. They fill the missing
```ts
import { Observable } from 'rxjs';

const observable = new Observable((subscriber) => {
const observable = new Observable<number>((subscriber) => {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
Expand All @@ -28,7 +28,7 @@ To invoke the Observable and see these values, we need to _subscribe_ to it:
```ts
import { Observable } from 'rxjs';

const observable = new Observable((subscriber) => {
const observable = new Observable<number>((subscriber) => {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
Expand Down Expand Up @@ -127,7 +127,7 @@ You can write the same behavior above, but with Observables:
```ts
import { Observable } from 'rxjs';

const foo = new Observable((subscriber) => {
const foo = new Observable<number>((subscriber) => {
console.log('Hello');
subscriber.next(42);
});
Expand Down Expand Up @@ -208,7 +208,7 @@ Functions can only return one value. Observables, however, can do this:
```ts
import { Observable } from 'rxjs';

const foo = new Observable((subscriber) => {
const foo = new Observable<number>((subscriber) => {
console.log('Hello');
subscriber.next(42);
subscriber.next(100); // "return" another value
Expand Down Expand Up @@ -238,7 +238,7 @@ But you can also "return" values asynchronously:
```ts
import { Observable } from 'rxjs';

const foo = new Observable((subscriber) => {
const foo = new Observable<number>((subscriber) => {
console.log('Hello');
subscriber.next(42);
subscriber.next(100);
Expand Down Expand Up @@ -292,7 +292,7 @@ The following example creates an Observable to emit the string `'hi'` every seco
```ts
import { Observable } from 'rxjs';

const observable = new Observable(function subscribe(subscriber) {
const observable = new Observable<string>(function subscribe(subscriber) {
const id = setInterval(() => {
subscriber.next('hi');
}, 1000);
Expand All @@ -311,9 +311,9 @@ The Observable `observable` in the example can be _subscribed_ to, like this:
observable.subscribe((x) => console.log(x));
```

It is not a coincidence that `observable.subscribe` and `subscribe` in `new Observable(function subscribe(subscriber) {...})` have the same name. In the library, they are different, but for practical purposes you can consider them conceptually equal.
It is not a coincidence that `observable.subscribe` and `subscribe` in `new Observable<unknown>(function subscribe(subscriber) {...})` have the same name. In the library, they are different, but for practical purposes you can consider them conceptually equal.

This shows how `subscribe` calls are not shared among multiple Observers of the same Observable. When calling `observable.subscribe` with an Observer, the function `subscribe` in `new Observable(function subscribe(subscriber) {...})` is run for that given subscriber. Each call to `observable.subscribe` triggers its own independent setup for that given subscriber.
This shows how `subscribe` calls are not shared among multiple Observers of the same Observable. When calling `observable.subscribe` with an Observer, the function `subscribe` in `new Observable<unknown>(function subscribe(subscriber) {...})` is run for that given subscriber. Each call to `observable.subscribe` triggers its own independent setup for that given subscriber.

<span class="informal">Subscribing to an Observable is like calling a function, providing callbacks where the data will be delivered to.</span>

Expand All @@ -323,7 +323,7 @@ A `subscribe` call is simply a way to start an "Observable execution" and delive

### Executing Observables

The code inside `new Observable(function subscribe(subscriber) {...})` represents an "Observable execution", a lazy computation that only happens for each Observer that subscribes. The execution produces multiple values over time, either synchronously or asynchronously.
The code inside `new Observable<unknown>(function subscribe(subscriber) {...})` represents an "Observable execution", a lazy computation that only happens for each Observer that subscribes. The execution produces multiple values over time, either synchronously or asynchronously.

There are three types of values an Observable Execution can deliver:

Expand All @@ -346,7 +346,7 @@ The following is an example of an Observable execution that delivers three Next
```ts
import { Observable } from 'rxjs';

const observable = new Observable(function subscribe(subscriber) {
const observable = new Observable<number>(function subscribe(subscriber) {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
Expand All @@ -359,7 +359,7 @@ Observables strictly adhere to the Observable Contract, so the following code wo
```ts
import { Observable } from 'rxjs';

const observable = new Observable(function subscribe(subscriber) {
const observable = new Observable<number>(function subscribe(subscriber) {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
Expand All @@ -373,7 +373,7 @@ It is a good idea to wrap any code in `subscribe` with `try`/`catch` block that
```ts
import { Observable } from 'rxjs';

const observable = new Observable(function subscribe(subscriber) {
const observable = new Observable<number>(function subscribe(subscriber) {
try {
subscriber.next(1);
subscriber.next(2);
Expand Down Expand Up @@ -415,7 +415,7 @@ For instance, this is how we clear an interval execution set with `setInterval`:
```ts
import { Observable } from 'rxjs';

const observable = new Observable(function subscribe(subscriber) {
const observable = new Observable<string>(function subscribe(subscriber) {
// Keep track of the interval resource
const intervalId = setInterval(() => {
subscriber.next('hi');
Expand All @@ -428,7 +428,7 @@ const observable = new Observable(function subscribe(subscriber) {
});
```

Just like `observable.subscribe` resembles `new Observable(function subscribe() {...})`, the `unsubscribe` we return from `subscribe` is conceptually equal to `subscription.unsubscribe`. In fact, if we remove the ReactiveX types surrounding these concepts, we're left with rather straightforward JavaScript.
Just like `observable.subscribe` resembles `new Observable<unknown>(function subscribe() {...})`, the `unsubscribe` we return from `subscribe` is conceptually equal to `subscription.unsubscribe`. In fact, if we remove the ReactiveX types surrounding these concepts, we're left with rather straightforward JavaScript.

```ts
function subscribe(subscriber) {
Expand Down
55 changes: 26 additions & 29 deletions apps/rxjs.dev/content/guide/subject.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,16 @@ A "multicasted Observable" passes notifications through a Subject which may have

<span class="informal">A multicasted Observable uses a Subject under the hood to make multiple Observers see the same Observable execution.</span>

Under the hood, this is how the `multicast` operator works: Observers subscribe to an underlying Subject, and the Subject subscribes to the source Observable. The following example is similar to the previous example which used `observable.subscribe(subject)`:
Under the hood, this is how the `connectable` operator works: Observers subscribe to an underlying Subject, and the Subject subscribes to the source Observable. The following example is similar to the previous example which used `observable.subscribe(subject)`:

```ts
import { from, Subject, multicast } from 'rxjs';
import { connectable, from, Subject } from 'rxjs';

const source = from([1, 2, 3]);
const subject = new Subject();
const multicasted = source.pipe(multicast(subject));
const subjectFactory = () => new Subject<number>();
const multicasted = connectable(source, {
connector: subjectFactory,
});

// These are, under the hood, `subject.subscribe({...})`:
multicasted.subscribe({
Expand All @@ -92,7 +94,7 @@ multicasted.subscribe({
multicasted.connect();
```

`multicast` returns an Observable that looks like a normal Observable, but works like a Subject when it comes to subscribing. `multicast` returns a `ConnectableObservable`, which is simply an Observable with the `connect()` method.
`connectable` returns an Observable that looks like a normal Observable, but works like a Subject when it comes to subscribing. `connectable` returns a `ConnectableObservable`, which is simply an Observable with the `connect()` method.

The `connect()` method is important to determine exactly when the shared Observable execution will start. Because `connect()` does `source.subscribe(subject)` under the hood, `connect()` returns a Subscription, which you can unsubscribe from in order to cancel the shared Observable execution.

Expand All @@ -116,12 +118,14 @@ Consider the following example where subscriptions occur as outlined by this lis
To achieve that with explicit calls to `connect()`, we write the following code:

```ts
import { interval, Subject, multicast } from 'rxjs';
import { connectable, interval, Subject, Subscription } from 'rxjs';

const source = interval(500);
const subject = new Subject();
const multicasted = source.pipe(multicast(subject));
let subscription1, subscription2, subscriptionConnect;
const subjectFactory = () => new Subject<number>();
const multicasted = connectable(source, {
connector: subjectFactory,
});
let subscription1, subscription2: Subscription, subscriptionConnect;

subscription1 = multicasted.subscribe({
next: (v) => console.log(`observerA: ${v}`),
Expand Down Expand Up @@ -155,12 +159,12 @@ If we wish to avoid explicit calls to `connect()`, we can use ConnectableObserva
Below is an example:

```ts
import { interval, Subject, multicast, refCount } from 'rxjs';
import { interval, Subject, Subscription, multicast, refCount } from 'rxjs';

const source = interval(500);
const subject = new Subject();
const subject = new Subject<number>();
const refCounted = source.pipe(multicast(subject), refCount());
let subscription1, subscription2;
let subscription1, subscription2: Subscription;

// This calls `connect()`, because
// it is the first subscriber to `refCounted`
Expand Down Expand Up @@ -211,10 +215,10 @@ In the following example, the BehaviorSubject is initialized with the value `0`

```ts
import { BehaviorSubject } from 'rxjs';
const subject = new BehaviorSubject(0); // 0 is the initial value
const subject = new BehaviorSubject(0); // 0 is the initial value - and its type is inferred automatically

subject.subscribe({
next: (v) => console.log(`observerA: ${v}`),
next: (v: number) => console.log(`observerA: ${v}`),
});

subject.next(1);
Expand Down Expand Up @@ -245,10 +249,10 @@ When creating a `ReplaySubject`, you can specify how many values to replay:

```ts
import { ReplaySubject } from 'rxjs';
const subject = new ReplaySubject(3); // buffer 3 values for new subscribers
const subject = new ReplaySubject<number>(3); // buffer 3 values for new subscribers

subject.subscribe({
next: (v) => console.log(`observerA: ${v}`),
next: (v: number) => console.log(`observerA: ${v}`),
});

subject.next(1);
Expand Down Expand Up @@ -280,10 +284,10 @@ You can also specify a _window time_ in milliseconds, besides of the buffer size

```ts
import { ReplaySubject } from 'rxjs';
const subject = new ReplaySubject(100, 500 /* windowTime */);
const subject = new ReplaySubject<number>(100, 500 /* windowTime */);

subject.subscribe({
next: (v) => console.log(`observerA: ${v}`),
next: (v: number) => console.log(`observerA: ${v}`),
});

let i = 1;
Expand Down Expand Up @@ -313,9 +317,9 @@ setTimeout(() => {

The AsyncSubject is a variant where only the last value of the Observable execution is sent to its observers, and only when the execution completes.

```js
```ts
import { AsyncSubject } from 'rxjs';
const subject = new AsyncSubject();
const subject = new AsyncSubject<number>();

subject.subscribe({
next: (v) => console.log(`observerA: ${v}`),
Expand Down Expand Up @@ -355,17 +359,10 @@ Passing a dummy value this way is clumsy and can confuse users.

By declaring a _void subject_, you signal that the value is irrelevant. Only the event itself matters.

```ts
const subject = new Subject<void>();
setTimeout(() => subject.next(), 1000);
```

A complete example with context is shown below:

```ts
import { Subject } from 'rxjs';

const subject = new Subject(); // Shorthand for Subject<void>
const subject = new Subject<void>();

subject.subscribe({
next: () => console.log('One second has passed'),
Expand All @@ -374,4 +371,4 @@ subject.subscribe({
setTimeout(() => subject.next(), 1000);
```

<span class="informal">Before version 7, the default type of Subject values was `any`. `Subject<any>` disables type checking of the emitted values, whereas `Subject<void>` prevents accidental access to the emitted value. If you want the old behavior, then replace `Subject` with `Subject<any>`.</span>
<span class="informal">Before version 7, the default type of Subject values was `any`. In v7+, the default type is `unknown`. `Subject<any>` disables type checking of the emitted values, whereas `Subject<unknown>` forces strict type-checking. Specifying an explicit type instead of the default is generally recommended.</span>