- vừa được xem lúc

Các best practice để phát triển Angular: Observable, Promise và Signals

0 0 7

Người đăng: Vũ Tuấn

Theo Viblo Asia

Angular đã có những tiến bộ đáng kể trong những năm qua, kết hợp với các nguyên tắc, công cụ và phương pháp mới để cải thiện năng suất của lập trình viên cũng như hiệu suất của ứng dụng. Các công cụ chính để xử lý các hoạt động bất đồng bộ trong phát triển Angular là Observable và Promise.

Cuộc tranh luận về việc sử dụng Observable so với Promise trong Angular vẫn chưa bao giờ là chủ đề không hấp dẫn, mỗi công cụ này đều có ưu và nhược điểm của nó tùy thuộc vào ngữ cảnh sử dụng. Ngoài ra, sự ra đời của Signals trong Angular đã cung cấp cho các lập trình viên nhiều lựa chọn hơn để quản lý các ứng dụng của họ.

Các hoạt động bất đồng bộ trong Angular

Các hoạt động bất đồng bộ cho phép ứng dụng vẫn phản hồi trong khi chờ các tác vụ hoàn thành, mà không ảnh hưởng đến luồng ứng dụng chính. Các ví dụ phổ biến bao gồm yêu cầu HTTP, I/O tệp và bộ hẹn giờ.

Xây dựng các ứng dụng hiệu suất và thân thiện với người dùng trong Angular đòi hỏi việc quản lý hiệu quả các hoạt động này. Việc lựa chọn giữa Observable và Promise phần lớn được quyết định bởi độ phức tạp của nhiệm vụ, bản chất của dữ liệu và nhu cầu về khả năng mở rộng.

Promise: Một cách tiếp cận trực tiếp đến các hoạt động không đồng bộ

1. Promise là gì?

Trong JavaScript, Promise là một cấu trúc biểu diễn giá trị có thể có ngay bây giờ, trong tương lai hoặc không bao giờ. Đây là trình xử lý sự kiện đơn được thiết kế để quản lý các hoạt động không đồng bộ. Promise có thể đặc biệt có lợi cho việc xử lý các hoạt động được cho là trả về một kết quả duy nhất, như lấy dữ liệu từ API.

Đặc điểm chính:

  • Sự kiện đơn: Promise xử lý một giá trị hoặc sự kiện đơn. Hoạt động hoàn tất khi được giải quyết hoặc từ chối.
  • Thực thi ngay lập tức: Promise bắt đầu thực thi ngay khi được tạo. Không thể tạm dừng hoặc hoãn lại.
  • Các đoạn mã đơn giản: Promise đơn giản hóa mã bất đồng bộ, đặc biệt khi sử dụng với async/await, giúp mã dễ đọc hơn và dễ quản lý hơn.

Ví dụ về Promise trong Angular:

async fetchData(): Promise<Data> { return await this.http.get<Data>('https://api.example.com/data').toPromise();
}

2. Ưu điểm của việc sử dụng Promises

  • Tính đơn giản: Promise rất rõ ràng và dễ hiểu, khiến chúng trở nên lý tưởng cho các tác vụ bất đồng bộ đơn giản hơn, không yêu cầu xử lý dữ liệu phức tạp.
  • Khả năng đọc: Khi kết hợp với async/await, Promise cho phép mã dễ đọc và bảo trì hơn, giống như lập trình đồng bộ.
  • Xử lý lỗi: Promise cung cấp cấu trúc rõ ràng để xử lý lỗi, sử dụng .catch() cho lỗi và .finally() để dọn dẹp.

3. Khi nào sử dụng Promises trong Angular?

Promise là một lựa chọn tốt cho:

  • Yêu cầu HTTP: Khi tác vụ liên quan đến một yêu cầu HTTP duy nhất trả về một phản hồi duy nhất, chẳng hạn như tìm nạp dữ liệu từ API REST.
  • Các hoạt động không đồng bộ một lần: Các hoạt động liên quan đến một bước duy nhất, chẳng hạn như đọc tệp hoặc tìm nạp dữ liệu người dùng khi khởi động ứng dụng.
  • Tích hợp với API bên ngoài: Nhiều API web hiện đại, như fetch, trả về Promise theo mặc định, giúp việc sử dụng Promise trong các bối cảnh như vậy trở nên tự nhiên.

Observables: Xử lý nâng cao các luồng dữ liệu không đồng bộ

1. Observables là gì?

Observable là một tính năng mạnh mẽ hơn được cung cấp bởi thư viện RxJS, nhằm giúp biểu diễn một chuỗi các sự kiện hoặc dữ liệu theo thời gian. Không giống như Promise, Observable có thể phát ra nhiều giá trị, xử lý nhiều sự kiện và cung cấp khả năng thao tác dữ liệu nâng cao thông qua các toán tử.

Đặc điểm chính:

  • Nhiều lần phát xạ: Các giá trị quan sát được có thể phát ra nhiều giá trị theo thời gian, khiến chúng trở nên lý tưởng cho các tác vụ như luồng dữ liệu thời gian thực hoặc nhiều yêu cầu HTTP.
  • Thực thi lazy: Observable không bắt đầu phát ra giá trị cho đến khi nó được đăng ký rõ ràng, cung cấp khả năng kiểm soát thực thi tốt hơn.
  • Hệ sinh thái toán tử phong phú: RxJS cung cấp một bộ toán tử toàn diện giúp các nhà phát triển dễ dàng lọc, chuyển đổi, kết hợp và quản lý các luồng dữ liệu.

Ví dụ về Observable trong Angular:

getData(): Observable<Data> { return this.http.get<Data>('https://api.example.com/data');
}

2. Ưu điểm của việc sử dụng Observables

  • Tính linh hoạt: Các biến quan sát có tính linh hoạt cao hơn, đặc biệt là trong các tình huống mà nhiều giá trị hoặc sự kiện được mong đợi theo thời gian, chẳng hạn như kết nối WebSocket hoặc nguồn cấp dữ liệu thời gian thực.
  • Xử lý dữ liệu mạnh mẽ: Các toán tử RxJS như map, filter, mergeMap, và switchMapcung cấp các công cụ mạnh mẽ để chuyển đổi và kết hợp các luồng dữ liệu.
  • Hủy bỏ và quản lý tài nguyên: Không giống như Promise, Observable hỗ trợ việc hủy bỏ các hoạt động, điều này rất quan trọng để quản lý tài nguyên trong các tác vụ chạy lâu hoặc tương tác với người dùng.

3. Khi nào sử dụng Observables trong Angular?

Các Observables được là lựa chọn tốt cho:

  • Luồng dữ liệu thời gian thực: Các tác vụ yêu cầu cập nhật dữ liệu liên tục hoặc nhiều lần, chẳng hạn như tỷ số thể thao thời gian thực, ứng dụng trò chuyện hoặc giám sát dữ liệu cảm biến.
  • Quy trình làm việc không đồng bộ phức tạp: Các tình huống yêu cầu chuỗi hoạt động không đồng bộ phức tạp, chẳng hạn như kết hợp nhiều yêu cầu HTTP, xử lý tương tác của người dùng hoặc tích hợp với các dịch vụ WebSocket.
  • Xử lý lỗi nâng cao: Các tình huống cần kiểm soát chính xác việc xử lý lỗi, cơ chế thử lại hoặc chiến lược dự phòng.

Signals: Mô hình mới nổi trong Angular

1. Signals là gì?

Signals là một khái niệm tương đối mới trong Angular, được thiết kế để đơn giản hóa luồng dữ liệu phản ứng bằng cách cung cấp một giải pháp thay thế tích hợp hơn và ít phức tạp hơn cho Observables cho một số trường hợp sử dụng nhất định. Signals đặc biệt hữu ích để quản lý trạng thái phản ứng trong các ứng dụng Angular mà không cần đến RxJS.

Đặc điểm chính:

  • Tính đơn giản: Signals cung cấp một cách đơn giản để quản lý trạng thái phản ứng, giảm nhu cầu về các luồng dữ liệu phức tạp trong các tình huống đơn giản hơn.
  • Tích hợp khung: Không giống như Observables, dựa vào thư viện RxJS bên ngoài, Signals được tích hợp chặt chẽ hơn với khung Angular, mang lại trải nghiệm phát triển liền mạch hơn.
  • Trường hợp sử dụng: Signals lý tưởng cho các tình huống mà bạn cần phản ứng với những thay đổi trong trạng thái ứng dụng hoặc UI mà không cần sử dụng toàn bộ sức mạnh của RxJS.

2. Khi nào sử dụng Signals?

Signal đặc biệt hữu ích trong các trường hợp sau:

  • Quản lý trạng thái: Khi quản lý trạng thái cục bộ hoặc toàn cầu đòi hỏi khả năng phản ứng nhưng không liên quan đến việc chuyển đổi dữ liệu phức tạp.
  • Cập nhật UI: Đối với các thành phần UI phản ứng cần cập nhật dựa trên những thay đổi về trạng thái, Signals cung cấp một cách đơn giản và hiệu quả để kích hoạt các bản cập nhật này.
  • Đơn giản hóa cơ sở mã: Trong trường hợp không cần đến RxJS, Signals cung cấp phương pháp hợp lý hơn để xử lý phản ứng, giảm mã mẫu và cải thiện khả năng bảo trì mã.

So sánh Observable, Promise và Signals

1. Yêu cầu HTTP: Observable hay Promise?

Đối với các yêu cầu HTTP, sự lựa chọn giữa Observable và Promise thường phụ thuộc vào mức độ phức tạp của tác vụ cần thực hiện:

  • Cam kết về tính đơn giản: Nếu bạn mong đợi một phản hồi duy nhất và không phát sinh thêm dữ liệu nào nữa, việc sử dụng Promise có thể đơn giản hóa mã của bạn, đặc biệt là khi kết hợp với async/await.
  • Có thể quan sát để linh hoạt: Sử dụng Observable khi bạn dự đoán cần phải thao tác luồng dữ liệu, áp dụng chuyển đổi hoặc xử lý nhiều phát thải theo thời gian.

Ví dụ với Promise:

async fetchData(): Promise<Data> { return await this.http.get<Data>('https://api.example.com/data').toPromise();
}

Ví dụ với Observable:

getData(): Observable<Data> { return this.http.get<Data>('https://api.example.com/data').pipe( map(response => this.transformData(response)), catchError(error => this.handleError(error)) );
}

2. Dữ liệu thời gian thực: Observable hay Signal?

Đối với dữ liệu thời gian thực, sự lựa chọn giữa Observable và Signal phụ thuộc vào độ phức tạp và yêu cầu của tác vụ:

  • Dùng Observable đối với các luồng phức tạp: Khi xử lý dữ liệu thời gian thực đòi hỏi chuyển đổi phức tạp, lọc hoặc kết hợp với các luồng dữ liệu khác, thì Observable là lựa chọn tốt nhất.
  • Signal cho khả năng phản ứng đơn giản: Đối với các bản cập nhật phản ứng đơn giản hơn, chẳng hạn như thay đổi UI dựa trên trạng thái, Signals cung cấp giải pháp hiệu quả và tích hợp hơn.

3. Quản lý trạng thái: Observable hay Signal?

Khi quản lý trạng thái ứng dụng, sự lựa chọn giữa Observable và Signal bị ảnh hưởng bởi nhu cầu về khả năng phản ứng và tính phức tạp:

  • Dùng Signal cho sự đơn giản: Nếu nhu cầu quản lý trạng thái của bạn đơn giản, Tín hiệu cung cấp phương pháp dễ sử dụng và dễ bảo trì cho trạng thái phản ứng.
  • Dùng Observable đối với trạng thái phức tạp: Đối với các tình huống quản lý trạng thái phức tạp hơn, khi bạn cần kết hợp hoặc chuyển đổi các luồng trạng thái, thì Observable vẫn là một công cụ mạnh mẽ.

Quản lý đăng ký và tránh rò rỉ bộ nhớ

Một trong những cân nhắc chính khi sử dụng Observables trong Angular, đó là quản lý các đăng ký để tránh rò rỉ bộ nhớ. Các đăng ký không được quản lý đúng cách có thể dẫn đến rò rỉ tài nguyên, gây ra các vấn đề về hiệu suất theo thời gian.

1. Best practice:

Sử dụng AsyncPipe: Trong các mẫu Angular, AsyncPipe tự động đăng ký và hủy đăng ký khỏi Observables, giảm nguy cơ rò rỉ bộ nhớ. Điều này đặc biệt hữu ích trong các thành phần mà bạn đang liên kết luồng dữ liệu trực tiếp với UI.

<div *ngIf="data$ | async as data"> {{ data.name }}
</div>

Hủy đăng ký thủ công: Khi sử dụng đăng ký thủ công, hãy luôn đảm bảo rằng bạn hủy đăng ký khi thành phần bị hủy. Điều này có thể được quản lý bằng cách sử dụng lifecyclehook OnDestroyhook của Angular kết hợp với toán tử của RxJS takeUntil.

ngOnInit(): void { this.dataService.getData().pipe( takeUntil(this.destroy$) ).subscribe(data => { this.data = data; });
} ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete();
}

Kết luận Sự phát triển của Angular đã cung cấp cho các lập trình viên nhiều công cụ hơn để quản lý các hoạt động không đồng bộ và phản ứng. Observables vẫn là thành phần cốt lõi của mô hình lập trình phản ứng của Angular, trong khi Promises cung cấp sự đơn giản và dễ sử dụng cho nhiều tình huống phổ biến. Việc giới thiệu Signals đang chuyển đổi cách các nhà phát triển tiếp cận phản ứng, cung cấp giải pháp tích hợp và hợp lý hơn cho một số trường hợp sử dụng nhất định. Cảm ơn các bạn đã theo dõi.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Route in Angular JS

Router là một module được đặt tại @angular/router, cung cấp cho ứng dụng Angluar của chúng ta khả năng điều hướng và hiển thị nội dung phù hợp với địa chỉ URL. Với các ứng dụng web thông thường, việc điều hướng theo URL thường sẽ do phía server đảm nhiệm, giống như hình ảnh dưới đây là ví dụ với Rai

0 0 96

- vừa được xem lúc

Có gì mới trong Angular 11

Phiên bản Angular 11.0.0 được phát hành vào tháng 11 năm 2020. Bản phát hành chính Angular 11 cung cấp các bản cập nhật trên toàn bộ nền tảng, bao gồm CLI và các components.

0 0 102

- vừa được xem lúc

Pipe trong Angular

Xin chào tất cả mọi người, bài viết này minh xin giới thiệu về Pipe trong Angular, rất mong được mọi người theo dõi. 1) Pipe trong Angular là gì. . .

0 0 127

- vừa được xem lúc

Angular Reactive Forms: Cách sử dụng FormArray

Trong bài viết này chúng ta sẽ tìm hiểu khi nào và cách sử dụng FormArray, cả trong Component và trong Template, ngoài ra chúng ta sẽ xem cách để custom validation cho nó. Vì sao chúng ta cần sử dụng FormArray.

0 0 107

- vừa được xem lúc

RxJS và Reactive Programming

1 - Stream. Streams are a sequence of values over time.

0 0 356

- vừa được xem lúc

Mapping class Java với Angular Typescript model – Chưa bao giờ dễ đến thế

Xin chào mọi người hôm nay mình giới thiệu một loại đồ chơi cực xịn cực hay ho luôn, đây là một thư viện giúp cho mọi người tạo ra 1 class Typescript trong dự án Frontend ở đây mình lấy ví dụ là Angul

0 0 95