mergeMap → запускает все параллельно
concatMap → ждёт завершения предыдущего
switchMap → отменяет предыдущий
exhaustMap → игнорирует новые
This project was generated using Angular CLI version 22.1.3.
To start a local development server, run:
ng serveOnce the server is running, open your browser and navigate to http://localhost:4200/. The application will automatically reload whenever you modify any of the source files.
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
ng generate component component-nameFor a complete list of available schematics (such as components, directives, or pipes), run:
ng generate --helpTo build the project run:
ng buildThis will compile your project and store the build artifacts in the dist/ directory. By default, the production build optimizes your application for performance and speed.
To execute unit tests with the Vitest test runner, use the following command:
ng testFor end-to-end (e2e) testing, run:
ng e2eAngular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
For more information on using the Angular CLI, including detailed command references, visit the Angular CLI Overview and Command Reference page.
Да. И я бы не пытался просто пройти все пункты видео подряд. У тебя уже есть хорошее учебное приложение, и его можно постепенно превратить в Angular / RxJS Playground.
Кстати, с твоей текущей Angular 22-версией часть вещей из видео уже успела измениться: resource() и httpResource() стали stable, Signal Forms тоже стали stable, zoneless уже давно стал стандартным направлением Angular. (Angular)
Я бы добавлял темы вот так.
Сейчас у тебя есть очень удачный блок:
Mapping Operators
│
├── mergeMap
├── concatMap
├── switchMap
└── exhaustMap
Можно добавить вторую страницу:
Combination Operators
│
├── combineLatest
├── forkJoin
├── zip
└── withLatestFrom
Это тоже можно сделать интерактивно.
Например, две кнопки:
A: [1] [2] [3]
B: [10] [20] [30]
И наглядно показывать:
A1 + B1 → [1, 10]
A2 → [2, 10]
A3 → [3, 10]
B2 → [3, 20]
A1 + B1
A2 + B2
A3 + B3
Task A ──────────── complete
Task B ────── complete
Task C ───────────────── complete
↓
все результаты сразу
Это очень хорошее продолжение твоего текущего проекта.
Добавить:
catchError
retry
retryWhen
finalize
Например, дать пользователю кнопку:
Send Success
Send Error
И задача:
running
↓
50%
↓
❌ ERROR
А потом показать:
retry(2)
Визуально:
Attempt 1 → ❌ Error
Attempt 2 → ❌ Error
Attempt 3 → ✓ Success
Это, на мой взгляд, следующая лучшая тема после mapping operators.
Filtering Operators
│
├── filter
├── debounceTime
├── distinctUntilChanged
├── throttleTime
├── take
└── takeUntil
Особенно круто будет показать:
Поле поиска:
[ a ][ n ][ g ][ u ][ l ][ a ][ r ]
И рядом:
Input:
a
an
ang
angu
angul
angula
angular
API request:
🔍 angular
То есть человек быстро печатает:
a → an → ang → angu → angular
Но запрос выполняется только после паузы.
У тебя сейчас switchMap показывает отмену искусственной задачи.
Можно сделать реальный пример:
Search:
[ angular ]
Typing:
a
an
ang
angu
Каждый ввод:
input$
↓
debounceTime(300)
↓
distinctUntilChanged()
↓
switchMap()
↓
HTTP Request
И визуально:
Request "a" ❌ cancelled
Request "an" ❌ cancelled
Request "ang" ❌ cancelled
Request "angular" ✓ completed
Вот это будет вообще идеальный пример того, зачем существует switchMap в реальной жизни.
Можно добавить страницу:
Operator Comparison
И дать один общий input:
Source:
[ Send 1 ]
[ Send 2 ]
[ Send 3 ]
А ниже четыре колонки:
┌─────────────┬─────────────┬─────────────┬─────────────┐
│ mergeMap │ concatMap │ switchMap │ exhaustMap │
├─────────────┼─────────────┼─────────────┼─────────────┤
│ Task 1 ████ │ Task 1 ████ │ Task 1 ❌ │ Task 1 ████ │
│ Task 2 ██ │ Task 2 ⏳ │ Task 2 ❌ │ Task 2 🚫 │
│ Task 3 █ │ Task 3 ⏳ │ Task 3 ████ │ Task 3 🚫 │
└─────────────┴─────────────┴─────────────┴─────────────┘
У тебя, по сути, уже почти такая страница есть.
У тебя уже используется:
signal()Но пока можно отдельно изучить:
signal()
computed()
effect()
linkedSignal()Например:
const firstName = signal('John');
const lastName = signal('Smith');
const fullName = computed(() =>
`${firstName()} ${lastName()}`
);UI:
First name: [John]
Last name: [Smith]
Full name:
John Smith
Меняем:
John → Mike
И:
fullName
автоматически меняется.
Например:
Users:
Alice
Bob
Charlie
Выбираем:
Selected User: Bob
Потом список пользователей меняется — linkedSignal может поддерживать связанное состояние. Angular прямо относит linkedSignal к современному реактивному API, и сейчас он уже production-ready. (Angular)
Вот это я бы тебе очень рекомендовал.
Ты уже фактически используешь такую архитектуру:
Observable
↓
subscribe()
↓
Signal
↓
Template
Можно изучить более современный подход:
toSignal()
toObservable()
Например:
const tasks = toSignal(
this.mappingDemoService.source$,
{
initialValue: []
}
);Или:
const source$ = toObservable(this.mySignal);Тогда отдельная страница:
RxJS ↔ Signals
Это можно прямо добавить в твой проект.
Например, Mapping Demo не грузить сразу:
@defer {
<app-merge-map />
} @placeholder {
<p>Mapping Demo will load soon...</p>
} @loading {
<p>Loading...</p>
}@defer действительно предназначен для отложенной загрузки части приложения и может уменьшать initial bundle; у него есть @placeholder, @loading и @error. (Angular)
Например:
User ID:
[ 1 ]
Меняем:
1 → 2 → 3
И Angular Resource сам управляет состоянием:
idle
loading
resolved
error
У Resource есть signal-состояния вроде:
resource.value()
resource.status()
resource.error()
resource.isLoading()Это хороший современный Angular-паттерн для асинхронных данных. (Angular)
Вот это я бы обязательно добавил.
Например:
src
├── merge-map.ts
├── merge-map.spec.ts
│
├── concat-map.ts
├── concat-map.spec.ts
│
├── switch-map.ts
├── switch-map.spec.ts
│
└── exhaust-map.ts
И тестировать Marble Diagrams:
source: --a----b----c---|
Например:
switchMap:
--A--B--C
↓
после нового значения предыдущий поток отменяется
Это поможет понять RxJS ещё глубже, чем визуальная страница.
RxJS Playground
│
├── Subject Demo
│ ├── Subject
│ ├── BehaviorSubject
│ ├── ReplaySubject
│ └── AsyncSubject
│
├── Mapping Demo
│ ├── mergeMap
│ ├── concatMap
│ ├── switchMap
│ └── exhaustMap
│
├── Filtering Demo
│ ├── debounceTime
│ ├── throttleTime
│ ├── filter
│ └── distinctUntilChanged
│
├── Combination Demo
│ ├── combineLatest
│ ├── forkJoin
│ ├── zip
│ └── withLatestFrom
│
├── Error Handling Demo
│ ├── catchError
│ ├── retry
│ ├── retryWhen
│ └── finalize
│
├── Signals Demo
│ ├── signal
│ ├── computed
│ ├── effect
│ └── linkedSignal
│
└── Angular Modern Demo
├── @defer
├── resource
├── toSignal
└── toObservable
Мой личный порядок для тебя сейчас был бы такой:
1. Закончить Mapping Demo
↓
2. Filtering Operators
↓
3. Combination Operators
↓
4. Error Handling
↓
5. Signals глубже
↓
6. RxJS ↔ Signals
↓
7. resource()
↓
8. @defer
↓
9. Unit tests
Именно так твой текущий маленький пример постепенно превратится в очень хороший личный учебный Angular/RxJS playground, а не в набор разрозненных примеров из YouTube. Angular сейчас активно развивает именно эти современные направления — Signals, async Resources, Signal Forms и zoneless change detection. (Angular)