0
0
Lập trình
Admin Team
Admin Teamtechmely

Tối Ưu Hóa Angular Signals với Kiểm Tra Đối Tượng Thông Minh

Đăng vào 4 ngày trước

• 4 phút đọc

Tối Ưu Hóa Angular Signals với Kiểm Tra Đối Tượng Thông Minh

Giới Thiệu

Trong Angular, Signals là một công cụ mạnh mẽ để xử lý tính năng phản ứng (reactivity). Tuy nhiên, nếu không được quản lý cẩn thận, chúng có thể gây ra những cập nhật không cần thiết, yêu cầu lãng phí và các vấn đề về hiệu suất. Bài viết này sẽ khám phá cách Signals phát ra các cập nhật, tầm quan trọng của việc kiểm tra sự bằng nhau (equal) và cách triển khai các chiến lược so sánh sâu hiệu quả để giữ cho ứng dụng của bạn mượt mà và đáng tin cậy.

Cách Signals Phát Ra Cập Nhật

Mỗi khi tham chiếu thay đổi, Signal được coi là “bẩn” và tất cả các Signal phụ, DOM, và các hàm effect cũng sẽ cập nhật. Điều này có thể dẫn đến việc cập nhật không cần thiết nếu không có biện pháp kiểm tra hợp lý.

Ngăn Ngừa Cập Nhật Không Cần Thiết với equal

Để tránh các cập nhật không cần thiết trong pipeline của Signal, bạn có thể sử dụng tùy chọn equal để định nghĩa logic so sánh một cách thủ công. Điều này có vẻ đơn giản với các đối tượng nông, nhưng với các đối tượng sâu, công việc trở nên nặng nề và khó duy trì hơn.

Tài Nguyên Angular và Cập Nhật Phiền Phức từ Nguồn

Vấn đề tương tự cũng tồn tại với Angular Resource. Bạn có thể sử dụng Signal như một nguồn cho tùy chọn params. Điều này kích hoạt một cuộc gọi bất đồng bộ mỗi khi Signal phát ra một giá trị mới. Tuy nhiên, mỗi cuộc gọi mới hủy bỏ cuộc gọi trước đó (tương tự như switchMap trong RxJS). Điều này không chỉ gây ra các yêu cầu không cần thiết mà còn loại bỏ giá trị trước đó khỏi Resource, có thể dẫn đến các hiệu ứng phụ kỳ lạ như việc hiển thị trang không ổn định.

Hiệu Suất của equal với Các Đối Tượng Lồng Ghép Sâu

Để ngăn ngừa các cập nhật không cần thiết, bạn có thể thêm các kiểm tra sự bằng nhau thủ công trước khi gọi mySignal.set(...) hoặc mySignal.update(...). Nhưng điều này dễ bị quên. Đó là lý do tại sao tôi thích sử dụng tùy chọn equal:

javascript Copy
signal({ id: 1 }, { equal: (a, b) => a.id === b.id });

Tuy nhiên, khi xử lý các đối tượng lồng ghép sâu, các kiểm tra sự bằng nhau có thể trở nên tốn kém. Andrew Jarrett đã khám phá ra giải pháp JavaScript nhanh nhất cho so sánh bằng nhau sâu, điều này có thể hữu ích.

Cách Tạo So Sánh Bằng Nhau Sâu Nhanh Nhất Trong JavaScript

Dưới đây là bài viết của anh ấy: Cách xây dựng hàm “deep equals” nhanh nhất trong JavaScript. Giải pháp trông như sau:

javascript Copy
const addressEquals = Function(
  "x",
  "y",
  `
  if (x === y) return true
  if (x.street1 !== y.street1) return false
  if (x.street2 !== y.street2) return false
  if (x.city !== y.city) return false
  return true
`
);

Giải pháp này bao gồm việc bọc so sánh của bạn bên trong một chuỗi và đánh giá nó với constructor của Function. Phương pháp này nhanh chóng nhưng không an toàn về kiểu dữ liệu. Nếu hình dạng của đối tượng của bạn thay đổi, bạn có thể quên cập nhật chuỗi so sánh.

Nhưng ngay cả khi không an toàn về kiểu dữ liệu, tôi nghĩ rằng có thể tạo ra một bài kiểm tra kiểu riêng và sử dụng một bộ chuyển đổi kiểu tùy chỉnh để biến đổi đối tượng thành một chuỗi mục tiêu với cùng hình dạng của đối tượng của bạn.

typescript Copy
interface MyObject {...};
const MyObjectComparaisonString = `...` as const
type IsMyDeepEqualsStringCorrect = Expect<Equal<ToDeepEqualsComparaion<MyObjectType>, typeof MyObjectComparaisonString >>

Đây chỉ là một ý tưởng, nhưng nó có thể đủ cho nhu cầu của bạn.

Nếu bạn đã sử dụng một thư viện schema, thư viện này là hoàn hảo cho nhu cầu của bạn!

@traversable: Giải Pháp Đơn Giản cho Sự Bằng Nhau Sâu với Các Bộ Kiểm Tra Schema

Andrew Jarrett cũng đã tạo ra một thư viện giúp việc kiểm tra sự bằng nhau sâu trở nên đơn giản khi làm việc với các bộ kiểm tra schema. Sử dụng zod làm ví dụ:

javascript Copy
import { z } from "zod";
import { zx } from "@traversable/zod";

const Address = z.object({
  street1: z.string(),
  street2: z.optional(z.string()),
  city: z.string(),
});

// Tạo hàm so sánh bằng nhau sâu 👇
const addressEquals = zx.deepEqual(Address);

addressEquals(
  { street1: "221B Baker St", city: "London" },
  { street1: "221B Baker St", city: "London" }
); // => true

Khi được sử dụng với một Signal:

javascript Copy
const address = signal(..., { equal: addressEquals });
const streetViewFromAddressResource = resource({ params: address, ... });

Giờ đây, streetViewFromAddressResource chỉ được gọi khi địa chỉ thực sự thay đổi. Điều này hoạt động với nhiều thư viện schema khác nhau:

  • Zod
  • JSON Schema
  • ArkType
  • TypeBox
  • Valibot

Đây là một giải pháp sạch sẽ và phát triển cùng với schema của bạn mà không cần cập nhật thủ công.

Lưu ý: Hãy cẩn thận nếu đối tượng/schema của bạn chứa các hàm hoặc ngày tháng, cách chúng được xử lý có thể không chắc chắn.

👉 Nếu bạn thấy bài viết này hữu ích, đừng ngần ngại để lại một 👍 hoặc chia sẻ ý kiến của bạn trong phần bình luận — tôi rất muốn nghe phản hồi của bạn!


Nếu bạn không biết tôi, tôi là Romain Geffrault, và tôi thường xuyên chia sẻ nội dung về Angular/TypeScript/RxJs/Signal. Hãy xem các bài viết khác của tôi và theo dõi tôi trên LinkedIn Romain Geffrault.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào