- Angular 8 教程
- Angular 8 - 首頁
- Angular 8 - 簡介
- Angular 8 - 安裝
- 建立第一個應用程式
- Angular 8 - 架構
- Angular 元件和模板
- Angular 8 - 資料繫結
- Angular 8 - 指令
- Angular 8 - 管道
- Angular 8 - 響應式程式設計
- 服務和依賴注入
- Angular 8 - Http 客戶端程式設計
- Angular 8 - Angular Material
- 路由和導航
- Angular 8 - 動畫
- Angular 8 - 表單
- Angular 8 - 表單驗證
- 身份驗證和授權
- Angular 8 - Web Workers
- Service Workers 和 PWA
- Angular 8 - 伺服器端渲染
- Angular 8 - 國際化 (i18n)
- Angular 8 - 可訪問性
- Angular 8 - CLI 命令
- Angular 8 - 測試
- Angular 8 - Ivy 編譯器
- Angular 8 - 使用 Bazel 構建
- Angular 8 - 向後相容性
- Angular 8 - 工作示例
- Angular 9 - 新特性?
- Angular 8 有用資源
- Angular 8 - 快速指南
- Angular 8 - 有用資源
- Angular 8 - 討論
Angular 8 - 響應式程式設計
響應式程式設計是一種處理資料流和變化傳播的程式設計正規化。資料流可以是靜態的或動態的。靜態資料流的例子是陣列或資料集合。它將具有初始數量,並且不會更改。動態資料流的例子是事件發射器。事件發射器在事件發生時發出資料。最初,可能沒有事件,但隨著時間的推移,事件會發生並被髮出。
響應式程式設計使資料流能夠從稱為Observable的一個源發出,並透過稱為訂閱的過程由稱為Observer的其他源捕獲發出的資料流。這種 Observable/Observer 模式或簡單的Observer模式極大地簡化了程式設計環境中複雜的變化檢測和必要的更新。
JavaScript 本身並不支援響應式程式設計。RxJs是一個使 JavaScript 能夠進行響應式程式設計的 JavaScript 庫。Angular 廣泛使用RxJs庫來實現以下高階概念:
- 元件之間的資料傳輸。
- HTTP 客戶端。
- 路由器。
- 響應式表單。
讓我們在本節中使用RxJs庫學習響應式程式設計。
Observable
如前所述,Observable是資料來源,它們可以是靜態的或動態的。Rxjs提供了許多從常用 JavaScript 物件建立Observable的方法。讓我們看看一些常見的方法。
of - 按順序發出任意數量的值,最後發出完成通知。
const numbers$ = of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
這裡:
numbers$是一個Observable物件,訂閱時將按順序發出 1 到 10。
變數末尾的美元符號 ($)用於標識該變數是 Observable。
range - 按順序發出一定範圍的數字。
const numbers$ = range(1,10)
from - 發出陣列、Promise 或可迭代物件。
const numbers$ = from([1,2,3,4,5,6,7,8,9,10]);
ajax - 透過 AJAX 獲取 url,然後發出響應。
const api$ = ajax({ url: 'https://httpbin.org/delay/1', method: 'POST', headers: { 'Content-Type': 'application/text' }, body: "Hello" });
這裡:
https://httpbin.org 是一款免費的 REST API 服務,它將以 JSON 格式返回提供的正文內容,如下所示:
{
"args": {},
"data": "Hello",
"files": {},
"form": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-US,en;q=0.9",
"Host": "httpbin.org", "Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36",
"X-Amzn-Trace-Id": "Root=1-5eeef468-015d8f0c228367109234953c"
},
"origin": "ip address",
"url": "https://httpbin.org/delay/1"
}
fromEvent - 監聽 HTML 元素的事件,然後在監聽的事件觸發時發出事件及其屬性。
const clickEvent$ = fromEvent(document.getElementById('counter'), 'click');
Angular 在內部廣泛使用此概念來提供元件之間的資料傳輸和響應式表單。
訂閱過程
訂閱 Observable 非常容易。每個 Observable 物件都有一個用於訂閱過程的方法,subscribe。Observer 需要實現三個回撥函式來訂閱 Observable 物件。它們如下所示:
next - 接收和處理從 Observable 發出的值
error - 錯誤處理回撥
complete - 當 Observable 中的所有資料都發出時呼叫的回撥函式。
定義完這三個回撥函式後,必須呼叫 Observable 的 subscribe 方法,如下所示:
const numbers$ = from([1,2,3,4,5,6,7,8,9,10]);
// observer
const observer = {
next: (num: number) => { this.numbers.push(num); this.val1 += num },
error: (err: any) => console.log(err),
complete: () => console.log("Observation completed")
};
numbers$.subscribe(observer);
這裡:
next - 方法獲取發出的數字,然後將其推入區域性變數this.numbers中。
next - 方法還將數字新增到區域性變數this.val1中。
error - 方法只是將錯誤訊息寫入控制檯。
complete - 方法也向控制檯寫入完成訊息。
我們可以跳過error和complete方法,只編寫next方法,如下所示:
number$.subscribe((num: number) => { this.numbers.push(num); this.val1 += num; });
運算子
Rxjs庫提供了一些運算子來處理資料流。一些重要的運算子如下:
filter - 使用回撥函式過濾資料流。
const filterFn = filter( (num : number) => num > 5 );
const filteredNumbers$ = filterFn(numbers$);
filteredNumbers$.subscribe( (num : number) => {
this.filteredNumbers.push(num); this.val2 += num } );
map - 使用回撥函式對映資料流並更改資料流本身。
const mapFn = map( (num : number) => num + num ); const mappedNumbers$ = mappedFn(numbers$);
pipe - 使能夠組合兩個或多個運算子。
const filterFn = filter( (num : number) => num > 5 );
const mapFn = map( (num : number) => num + num ); const processedNumbers$ = numbers$.pipe(filterFn, mapFn);
processedNumbers$.subscribe( (num : number) => { this.processedNumbers.push(num); this.val3 += num } );
讓我們建立一個示例應用程式來試用本章中學習的響應式程式設計概念。
使用以下命令建立一個新的應用程式 reactive:
ng new reactive
將目錄更改為我們新建立的應用程式。
cd reactive
執行應用程式。
ng serve
更改 AppComponent 元件程式碼 (src/app/app.component.ts),如下所示:
import { Component, OnInit } from '@angular/core'; import { Observable, of, range, from, fromEvent } from 'rxjs';
import { ajax } from 'rxjs/ajax';
import { filter, map, catchError } from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'Reactive programming concept';
numbers : number[] = [];
val1 : number = 0;
filteredNumbers : number[] = [];
val2 : number = 0;
processedNumbers : number[] = [];
val3 : number = 0;
apiMessage : string;
counter : number = 0;
ngOnInit() {
// Observable stream of data Observable<number>
// const numbers$ = of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// const numbers$ = range(1,10);
const numbers$ = from([1,2,3,4,5,6,7,8,9,10]);
// observer
const observer = {
next: (num: number) => {this.numbers.push(num); this.val1 += num },
error: (err: any) => console.log(err),
complete: () => console.log("Observation completed")
};
numbers$.subscribe(observer);
const filterFn = filter( (num : number) => num > 5 );
const filteredNumbers = filterFn(numbers$);
filteredNumbers.subscribe( (num : number) => {this.filteredNumbers.push(num); this.val2 += num } );
const mapFn = map( (num : number) => num + num );
const processedNumbers$ = numbers$.pipe(filterFn, mapFn);
processedNumbers$.subscribe( (num : number) => {this.processedNumbers.push(num); this.val3 += num } );
const api$ = ajax({
url: 'https://httpbin.org/delay/1',
method: 'POST',
headers: {'Content-Type': 'application/text' },
body: "Hello"
});
api$.subscribe(res => this.apiMessage = res.response.data );
const clickEvent$ = fromEvent(document.getElementById('counter'), 'click');
clickEvent$.subscribe( () => this.counter++ );
}
}
這裡:
- 使用 of、range、from、ajax 和 fromEvent 方法建立 Observable。
- 使用 filter、map 和 pipe 運算子方法處理資料流。
- 回撥函式捕獲發出的資料,處理它,然後將其儲存在元件的區域性變數中。
更改AppComponent模板(src/app/app.component.html),如下所示:
<h1>{{ title }}</h1>
<div>
The summation of numbers ( <span *ngFor="let num of numbers"> {{ num }} </span> ) is {{ val1 }}
</div>
<div>
The summation of filtered numbers ( <span *ngFor="let num of filteredNumbers"> {{ num }} </span> ) is {{ val2 }}
</div>
<div>
The summation of processed numbers ( <span *ngFor="let num of processedNumbers"> {{ num }} </span> ) is {{ val3 }}
</div>
<div>
The response from the API is <em>{{ apiMessage }}</em> </div>
<div>
<a id="counter" href="#">Click here</a> to increment the counter value. The current counter value is {{ counter }}
<div>
這裡:
顯示Observer回撥函式處理的所有區域性變數。
開啟瀏覽器,https://:4200。
單擊單擊此處連結五次。對於每個事件,都會發出事件並轉發到Observer。將呼叫 Observer 回撥函式。回撥函式會為每次點選遞增計數器,最終結果如下所示: