Skip to content

Commit

Permalink
docs(observable.md): add missing import (#7026)
Browse files Browse the repository at this point in the history
  • Loading branch information
jakovljevic-mladen authored Aug 10, 2022
1 parent e13913c commit 3838af8
Showing 1 changed file with 48 additions and 40 deletions.
88 changes: 48 additions & 40 deletions docs_app/content/guide/observable.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

Observables are lazy Push collections of multiple values. They fill the missing spot in the following table:

| | Single | Multiple |
| --- | --- | --- |
| **Pull** | [`Function`](https://developer.mozilla.org/en-US/docs/Glossary/Function) | [`Iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) |
| **Push** | [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) | [`Observable`](/api/index/class/Observable) |
| | Single | Multiple |
| -------- | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| **Pull** | [`Function`](https://developer.mozilla.org/en-US/docs/Glossary/Function) | [`Iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) |
| **Push** | [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) | [`Observable`](/api/index/class/Observable) |

**Example.** The following is an Observable that pushes the values `1`, `2`, `3` immediately (synchronously) when subscribed, and the value `4` after one second has passed since the subscribe call, then completes:

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

const observable = new Observable(subscriber => {
const observable = new Observable((subscriber) => {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
Expand All @@ -23,12 +23,12 @@ const observable = new Observable(subscriber => {
});
```

To invoke the Observable and see these values, we need to *subscribe* to it:
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((subscriber) => {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
Expand All @@ -40,9 +40,15 @@ const observable = new Observable(subscriber => {

console.log('just before subscribe');
observable.subscribe({
next(x) { console.log('got value ' + x); },
error(err) { console.error('something wrong occurred: ' + err); },
complete() { console.log('done'); }
next(x) {
console.log('got value ' + x);
},
error(err) {
console.error('something wrong occurred: ' + err);
},
complete() {
console.log('done');
},
});
console.log('just after subscribe');
```
Expand All @@ -61,19 +67,18 @@ done

## Pull versus Push

*Pull* and *Push* are two different protocols that describe how a data *Producer* can communicate with a data *Consumer*.
_Pull_ and _Push_ are two different protocols that describe how a data _Producer_ can communicate with a data _Consumer_.

**What is Pull?** In Pull systems, the Consumer determines when it receives data from the data Producer. The Producer itself is unaware of when the data will be delivered to the Consumer.

Every JavaScript Function is a Pull system. The function is a Producer of data, and the code that calls the function is consuming it by "pulling" out a *single* return value from its call.
Every JavaScript Function is a Pull system. The function is a Producer of data, and the code that calls the function is consuming it by "pulling" out a _single_ return value from its call.

ES2015 introduced [generator functions and iterators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*) (`function*`), another type of Pull system. Code that calls `iterator.next()` is the Consumer, "pulling" out *multiple* values from the iterator (the Producer).
ES2015 introduced [generator functions and iterators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*) (`function*`), another type of Pull system. Code that calls `iterator.next()` is the Consumer, "pulling" out _multiple_ values from the iterator (the Producer).


| | Producer | Consumer |
| --- | --- | --- |
| | Producer | Consumer |
| -------- | ------------------------------------------ | ------------------------------------------- |
| **Pull** | **Passive:** produces data when requested. | **Active:** decides when data is requested. |
| **Push** | **Active:** produces data at its own pace. | **Passive:** reacts to received data. |
| **Push** | **Active:** produces data at its own pace. | **Passive:** reacts to received data. |

**What is Push?** In Push systems, the Producer determines when to send data to the Consumer. The Consumer is unaware of when it will receive that data.

Expand All @@ -90,7 +95,7 @@ RxJS introduces Observables, a new Push system for JavaScript. An Observable is

## Observables as generalizations of functions

Contrary to popular claims, Observables are not like EventEmitters nor are they like Promises for multiple values. Observables *may act* like EventEmitters in some cases, namely when they are multicasted using RxJS Subjects, but usually they don't act like EventEmitters.
Contrary to popular claims, Observables are not like EventEmitters nor are they like Promises for multiple values. Observables _may act_ like EventEmitters in some cases, namely when they are multicasted using RxJS Subjects, but usually they don't act like EventEmitters.

<span class="informal">Observables are like functions with zero arguments, but generalize those to allow multiple values.</span>

Expand Down Expand Up @@ -122,15 +127,15 @@ You can write the same behavior above, but with Observables:
```ts
import { Observable } from 'rxjs';

const foo = new Observable(subscriber => {
const foo = new Observable((subscriber) => {
console.log('Hello');
subscriber.next(42);
});

foo.subscribe(x => {
foo.subscribe((x) => {
console.log(x);
});
foo.subscribe(y => {
foo.subscribe((y) => {
console.log(y);
});
```
Expand All @@ -150,7 +155,7 @@ This happens because both functions and Observables are lazy computations. If yo

Some people claim that Observables are asynchronous. That is not true. If you surround a function call with logs, like this:

```js
```ts
console.log('before');
console.log(foo.call());
console.log('after');
Expand All @@ -167,9 +172,9 @@ You will see the output:

And this is the same behavior with Observables:

```js
```ts
console.log('before');
foo.subscribe(x => {
foo.subscribe((x) => {
console.log(x);
});
console.log('after');
Expand All @@ -190,7 +195,7 @@ Which proves the subscription of `foo` was entirely synchronous, just like a fun

What is the difference between an Observable and a function? **Observables can "return" multiple values over time**, something which functions cannot. You can't do this:

```js
```ts
function foo() {
console.log('Hello');
return 42;
Expand All @@ -203,15 +208,15 @@ 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((subscriber) => {
console.log('Hello');
subscriber.next(42);
subscriber.next(100); // "return" another value
subscriber.next(200); // "return" yet another
});

console.log('before');
foo.subscribe(x => {
foo.subscribe((x) => {
console.log(x);
});
console.log('after');
Expand All @@ -233,7 +238,7 @@ But you can also "return" values asynchronously:
```ts
import { Observable } from 'rxjs';

const foo = new Observable(subscriber => {
const foo = new Observable((subscriber) => {
console.log('Hello');
subscriber.next(42);
subscriber.next(100);
Expand All @@ -244,7 +249,7 @@ const foo = new Observable(subscriber => {
});

console.log('before');
foo.subscribe(x => {
foo.subscribe((x) => {
console.log(x);
});
console.log('after');
Expand All @@ -264,14 +269,15 @@ With output:

Conclusion:

- `func.call()` means "*give me one value synchronously*"
- `observable.subscribe()` means "*give me any amount of values, either synchronously or asynchronously*"
- `func.call()` means "_give me one value synchronously_"
- `observable.subscribe()` means "_give me any amount of values, either synchronously or asynchronously_"

## Anatomy of an Observable

Observables are **created** using `new Observable` or a creation operator, are **subscribed** to with an Observer, **execute** to deliver `next` / `error` / `complete` notifications to the Observer, and their execution may be **disposed**. These four aspects are all encoded in an Observable instance, but some of these aspects are related to other types, like Observer and Subscription.

Core Observable concerns:

- **Creating** Observables
- **Subscribing** to Observables
- **Executing** the Observable
Expand All @@ -288,7 +294,7 @@ import { Observable } from 'rxjs';

const observable = new Observable(function subscribe(subscriber) {
const id = setInterval(() => {
subscriber.next('hi')
subscriber.next('hi');
}, 1000);
});
```
Expand All @@ -299,10 +305,10 @@ In the example above, the `subscribe` function is the most important piece to de

### Subscribing to Observables

The Observable `observable` in the example can be *subscribed* to, like this:
The Observable `observable` in the example can be _subscribed_ to, like this:

```ts
observable.subscribe(x => console.log(x));
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.
Expand All @@ -327,7 +333,7 @@ There are three types of values an Observable Execution can deliver:

"Next" notifications are the most important and most common type: they represent actual data being delivered to a subscriber. "Error" and "Complete" notifications may happen only once during the Observable Execution, and there can only be either one of them.

These constraints are expressed best in the so-called *Observable Grammar* or *Contract*, written as a regular expression:
These constraints are expressed best in the so-called _Observable Grammar_ or _Contract_, written as a regular expression:

```none
next*(error|complete)?
Expand Down Expand Up @@ -386,7 +392,7 @@ Because Observable Executions may be infinite, and it's common for an Observer t
When `observable.subscribe` is called, the Observer gets attached to the newly created Observable execution. This call also returns an object, the `Subscription`:

```ts
const subscription = observable.subscribe(x => console.log(x));
const subscription = observable.subscribe((x) => console.log(x));
```

The Subscription represents the ongoing execution, and has a minimal API which allows you to cancel that execution. Read more about the [`Subscription` type here](./guide/subscription). With `subscription.unsubscribe()` you can cancel the ongoing execution:
Expand All @@ -395,7 +401,7 @@ The Subscription represents the ongoing execution, and has a minimal API which a
import { from } from 'rxjs';

const observable = from([10, 20, 30]);
const subscription = observable.subscribe(x => console.log(x));
const subscription = observable.subscribe((x) => console.log(x));
// Later:
subscription.unsubscribe();
```
Expand All @@ -406,7 +412,9 @@ Each Observable must define how to dispose resources of that execution when we c

For instance, this is how we clear an interval execution set with `setInterval`:

```js
```ts
import { Observable } from 'rxjs';

const observable = new Observable(function subscribe(subscriber) {
// Keep track of the interval resource
const intervalId = setInterval(() => {
Expand All @@ -422,7 +430,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.

```js
```ts
function subscribe(subscriber) {
const intervalId = setInterval(() => {
subscriber.next('hi');
Expand All @@ -433,7 +441,7 @@ function subscribe(subscriber) {
};
}

const unsubscribe = subscribe({next: (x) => console.log(x)});
const unsubscribe = subscribe({ next: (x) => console.log(x) });

// Later:
unsubscribe(); // dispose the resources
Expand Down

0 comments on commit 3838af8

Please sign in to comment.