Reactive Programming
เมื่อคุณฟอล ig สาว คุณกำลัง Observe สาว
Reactive Programming คือแนวคิดในการเขียนโปรแกรมที่เน้นการทำงานกับข้อมูลที่ส่งมาแบบ asynchronousโดยสร้างระบบที่ตอบสนองต่อ changes หรือ events ที่เกิดขึ้น
changes หรือ events ที่เกิดขึ้นในระบบ จะเกิด side effect เสมอ
Key Concepts
- Observables: เป็นแหล่งกำเนิดของการไหลของข้อมูล (data streams) หรือเหตุการณ์ต่าง ๆ
- Observers: subscribe ไปที่ Observables เพื่อรับข้อมูลและตอบสนองต่อการเปลี่ยนแปลง
- Operators: ใช้ในการประมวลผลและเปลี่ยนแปลงข้อมูลใน data streams ก่อนที่จะส่งไปยัง Observers
- Schedulers: จัดการบริบทของการดำเนินงานของ Observables และ Observers เพื่อกำหนดว่าข้อมูลจะถูกประมวลผลอย่างไรและเมื่อใด
อธิบายเพิ่มเพื่อให้เข้าใจความสัมพันธ์ระหว่าง Key Concepts แต่ละตัว
1. Observables
Observables เป็นตัวแทนของการไหลของข้อมูลหรือเหตุการณ์ที่สามารถถูก observe ได้ โดยข้อมูลหรือเหตุการณ์เหล่านี้สามารถเป็นได้ทั้งแบบ synchronous และ asynchronous
Observables ยังทำหน้าที่เป็นแหล่งกำเนิดของข้อมูลที่สามารถส่งค่าต่าง ๆ ไปยัง Observers
ตัวอย่างเช่น
• การคลิกเมาส์ (mouse clicks)
• การอัปเดตข้อมูลแบบเรียลไทม์ (real-time data updates)
• การอ่านค่าจากเซ็นเซอร์ (sensor readings)
2. Observers
Observers คือผู้ที่ทำการตอบสนองต่อการเปลี่ยนแปลงใน Observables โดยจะทำการ subscribe ไปที่ Observables และรอรับข้อมูลหรือเหตุการณ์ที่ถูกส่งมา
เมื่อ Observables มีการเปลี่ยนแปลงหรือต้องการส่งข้อมูล Observers จะทำการประมวลผลหรือตอบสนองต่อข้อมูลเหล่านั้น
ตัวอย่างเช่น
• การอัปเดต UI เมื่อมีการคลิกเมาส์
• การแสดงข้อมูล real-time
• การแจ้งเตือนผู้ใช้เมื่อมีเหตุการณ์เกิดขึ้น
3. Operators
Operators คือฟังก์ชันที่สามารถใช้ในการ manipulate และ transform data streams (การไหลของข้อมูล) ใน Observables
Operators ทำให้สามารถประมวลผลข้อมูลได้หลายรูปแบบ เช่น filtering, mapping, reducing เป็นต้น
Operators จะถูกใช้ในลำดับการทำงานของ Observables ก่อนที่ข้อมูลจะถูกส่งไปยัง Observers
ตัวอย่างเช่น
• filter เพื่อกรองข้อมูลที่ไม่ต้องการออก
• map เพื่อเปลี่ยนแปลงค่าของข้อมูล
• merge เพื่อรวมข้อมูลจากหลาย Observables
4. Schedulers
Schedulers ทำหน้าที่จัดการการไหลของข้อมูล (data streams) และการทำงานของ Observers โดยการกำหนดบริบทของการดำเนินงาน Schedulers จะควบคุมว่าเมื่อใดและอย่างไรที่ Observables และ Observers จะทำงาน เช่น การกำหนดว่า Observables จะทำงานใน thread ไหน หรือจะทำงานในลักษณะ synchronous หรือ asynchronous
ตัวอย่างเช่น
• กำหนดให้ Observables ทำงานใน thread background เพื่อไม่ให้ block UI
• การทำงานของ Observers ใน context ที่กำหนด
When to use Reactive Programming
การเขียนโปรแกรมแบบ Reactive เหมาะสมกับงานหลายประเภทที่ต้องจัดการกับข้อมูลหรือเหตุการณ์แบบ asynchronous อย่างมีประสิทธิภาพ ซึ่งรวมถึงงานต่าง ๆ เช่น :
1. งานที่เกี่ยวข้องกับ User Interfaces
การสร้าง UI ที่ตอบสนองต่อการกระทำของผู้ใช้ในทันที เช่น:
• การอัปเดตส่วนต่าง ๆ ของหน้าเว็บหรือแอปพลิเคชันเมื่อผู้ใช้ทำการคลิก, กรอกข้อมูล หรือเลื่อนหน้า
• การสร้างแบบฟอร์มที่สามารถตรวจสอบข้อมูลได้ในขณะกรอก
• การทำงานของแอปพลิเคชันที่ต้องมีการโหลดข้อมูลแบบเรียลไทม์ เช่น การแสดงข้อมูลในแอปพลิเคชันตารางเวลา
2. งานที่ต้องการข้อมูลเรียลไทม์ (Real-Time Data)
งานที่ต้องการการอัปเดตข้อมูลอย่างต่อเนื่องและทันที เช่น:
• ระบบแชทและการส่งข้อความที่ต้องการการตอบสนองทันที
• การติดตามหุ้นหรือราคาสินทรัพย์ที่เปลี่ยนแปลงตลอดเวลา
• การแสดงข้อมูลสภาพอากาศแบบเรียลไทม์
3. Event-Driven Architectures
การสร้างระบบที่ตอบสนองต่อ events ต่าง ๆ เช่น:
• การแจ้งเตือนผู้ใช้เมื่อเกิดเหตุการณ์สำคัญ
• การจัดการเซ็นเซอร์และการอ่านค่าจากอุปกรณ์ IoT
• การจัดการการอัปเดตข้อมูลและการแจ้งเตือนในแอปพลิเคชันมือถือ
4. งานที่ต้องการการประมวลผลข้อมูลขนาดใหญ่และซับซ้อน
การรวมและประมวลผลข้อมูลจากแหล่งข้อมูลหลาย ๆ แห่ง เช่น:
• การรวมข้อมูลจาก API หลายตัวและทำการประมวลผลเพื่อแสดงผลในหน้าเดียวกัน
• การประมวลผลข้อมูลจากระบบแบ็คเอนด์ที่มีหลายแหล่งข้อมูล
• การวิเคราะห์ข้อมูลจากหลายแหล่งเพื่อสรุปผลในเวลาจริง
เปรียบเทียบระหว่าง Reactive และ Imperative Programming
เพื่อทำความเข้าใจความแตกต่างระหว่างการเขียนโปรแกรมแบบ Reactive และแบบ Imperative เราจะใช้ตัวอย่างใน Angular ที่แสดงการจัดการกับข้อมูล asynchronous โดยเปรียบเทียบการเขียนโปรแกรมทั้งสองแบบ
import { Component, OnInit } from '@angular/core';
import { of } from 'rxjs';
import { map, filter } from 'rxjs/operators';
@Component({
selector: 'app-reactive-example',
template: `
<ul>
<li *ngFor="let number of numbers">{{ number }}</li>
</ul>
`
})
export class ReactiveExampleComponent implements OnInit {
numbers: number[] = [];
ngOnInit() {
const observable = of(1, 2, 3, 4, 5);
observable.pipe(
filter(num => num % 2 === 0),
map(num => num * 2)
).subscribe(result => {
this.numbers.push(result);
});
}
}
- Observable ถูกสร้างขึ้นด้วย
of
ซึ่งสร้างสตรีมของตัวเลข - Operators เช่น
filter
และmap
ถูกใช้ในการเปลี่ยนแปลงข้อมูลในสตรีม - Subscription ถูกใช้เพื่ออัปเดต
numbers
ใน component เมื่อข้อมูลถูกประมวลผล
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-imperative-example',
template: `
<ul>
<li *ngFor="let number of numbers">{{ number }}</li>
</ul>
`
})
export class ImperativeExampleComponent implements OnInit {
numbers: number[] = [];
ngOnInit() {
const data = [1, 2, 3, 4, 5];
const filteredData = this.filterEvenNumbers(data);
const transformedData = this.doubleNumbers(filteredData);
this.numbers = transformedData;
}
filterEvenNumbers(data: number[]): number[] {
const result = [];
for (let num of data) {
if (num % 2 === 0) {
result.push(num);
}
}
return result;
}
doubleNumbers(data: number[]): number[] {
const result = [];
for (let num of data) {
result.push(num * 2);
}
return result;
}
}
- ใช้การประมวลผลข้อมูลแบบขั้นตอน (procedural) โดยการกรองและเปลี่ยนแปลงข้อมูลในลำดับ
- filterEvenNumbers และ doubleNumbers ถูกเรียกเพื่อกรองและเปลี่ยนแปลงข้อมูล
- ผลลัพธ์สุดท้ายถูกเก็บใน
numbers
ซึ่งจะใช้ใน template
ข้อดีของการเขียนโปรแกรมแบบ Reactive
- การจัดการอะซิงโครนัสง่ายขึ้น: การใช้ Observables และ Operators ทำให้การจัดการกับข้อมูลที่มาจากหลายแหล่งและการตอบสนองต่อเหตุการณ์ทำได้ง่ายและเป็นธรรมชาติ
- การอ่านและบำรุงรักษาโค้ด: การเขียนโปรแกรมแบบ Declarative ทำให้โค้ดมีความชัดเจนและอ่านง่าย โดยเฉพาะในระบบที่ซับซ้อน
- ความสามารถในการขยายตัว: การจัดการข้อมูลและการตอบสนองต่อเหตุการณ์ทำได้ดีในระบบขนาดใหญ่และซับซ้อน
ข้อเสียของการเขียนโปรแกรมแบบ Reactive
- การเรียนรู้ที่ยากลำบาก: แนวคิดและวิธีการเขียนโค้ดแบบ Reactive อาจยากต่อการเข้าใจสำหรับผู้ที่ไม่มีประสบการณ์
- การ debug ที่ซับซ้อน: เนื่องจากการไหลของข้อมูลอาจมีความซับซ้อน ทำให้การดีบักและติดตามข้อผิดพลาดเป็นเรื่องยาก
- ประสิทธิภาพในบางกรณี: อาจมี overhead ในการใช้งาน Operators และ Observables เมื่อเทียบกับวิธีการแบบขั้นตอนที่ง่ายกว่า
ข้อดีของการเขียนโปรแกรมแบบ Imperative
- ความเรียบง่าย: ง่ายต่อการเริ่มต้นและเข้าใจ เนื่องจากการทำงานเป็นขั้นตอนที่ชัดเจน
- การ debug ที่ง่าย: การติดตามข้อผิดพลาดทำได้ง่ายกว่า เนื่องจากลำดับการทำงานเป็นขั้นตอนที่ชัดเจน
- ประสิทธิภาพ: มีประสิทธิภาพดีสำหรับงานที่ไม่ซับซ้อน และไม่ต้องการการจัดการข้อมูลอะซิงโครนัสจำนวนมาก
ข้อเสียของการเขียนโปรแกรมแบบ Imperative
- การจัดการอะซิงโครนัสที่ยากขึ้น: ต้องใช้ callback หรือ promises ซึ่งอาจทำให้โค้ดยุ่งเหยิง (callback hell)
- การบำรุงรักษาในระบบขนาดใหญ่: เมื่อระบบมีความซับซ้อนมากขึ้น การบำรุงรักษาโค้ดจะยากขึ้นและอาจมีข้อผิดพลาดมากขึ้น
- ความสามารถในการขยายตัว: อาจยากในการขยายระบบที่ซับซ้อนและต้องจัดการข้อมูลจำนวนมาก
การเลือกใช้ระหว่างการเขียนโปรแกรมแบบ Reactive และ Imperative ขึ้นอยู่กับลักษณะของงานและความต้องการของระบบ หากระบบมีการจัดการกับข้อมูล asynchronous และมีความซับซ้อนสูง การเขียนโปรแกรมแบบ Reactive อาจเป็นตัวเลือกที่ดีกว่า แต่หากเป็นงานที่ไม่ซับซ้อนและต้องการความง่ายในการเขียนและดีบัก การเขียนโปรแกรมแบบ Imperative อาจเหมาะสมกว่า
Conclusion
การเขียนโปรแกรมแบบ Reactive เป็นแนวคิดที่มีประสิทธิภาพในการจัดการกับข้อมูลและ events แบบ asynchronous โดยใช้ Observables, Observers, Operators และ Schedulers เป็นเครื่องมือหลักในการสร้างระบบที่ตอบสนองต่อการเปลี่ยนแปลงของข้อมูลได้อย่างทันทีและมีประสิทธิภาพ