Khi làm việc với ReactJS, khái niệm Virtual DOM (DOM ảo) chắc hẳn không còn xa lạ. Nhưng Virtual DOM là gì? Nó khác gì so với DOM thông thường? Liệu Virtual DOM có thực sự nhanh như lời đồn? Bài viết này sẽ giúp bạn hiểu rõ hơn về Virtual DOM trong ReactJS.
Minh họa về DOM và Virtual DOM
Mục Lục
DOM (Document Object Model) là gì?
DOM (Document Object Model – Mô hình Đối tượng Tài liệu) là một chuẩn được W3C (World Wide Web Consortium) định nghĩa để truy xuất và thao tác trên code HTML hoặc XML bằng các ngôn ngữ lập trình thông dịch (scripting language) như Javascript.
DOM giúp thao tác với dữ liệu theo mô hình hướng đối tượng. Các phần tử trong DOM có cấu trúc được định nghĩa thành các đối tượng, phương thức và thuộc tính, cho phép truy xuất dễ dàng. Chúng được coi như các node và được biểu diễn dưới dạng DOM Tree (cây DOM).
Trong khi HTML là một đoạn code, DOM là một thể hiện trừu tượng của đoạn code đó trong bộ nhớ.
Ví dụ về cấu trúc DOM:
-> document node
-> element node – head
HTML DOM -> text node
-> element node – title
-> element node – body
HTML DOM cung cấp API để duyệt và chỉnh sửa các node. Nó chứa các phương thức như getElementById hoặc removeChild.
var content = document.getElementById("myContent");
document.removeChild(item);
Đối với lập trình viên web, việc nắm vững kiến thức về DOM và khả năng thao tác với DOM mang lại sức mạnh thay đổi mọi thứ của trang web.
HTML DOM được cấu trúc dạng cây, cho phép duyệt cây dễ dàng. Tuy nhiên, việc duyệt cây dễ dàng không đồng nghĩa với tốc độ nhanh.
Cấu trúc cây DOM
Hiểu lầm về tốc độ của DOM
Nhiều người cho rằng việc đọc và ghi vào DOM của trình duyệt là chậm, nhưng điều này không hoàn toàn đúng. Bản thân DOM không chậm. Việc cập nhật các node trong DOM không mất nhiều thời gian hơn việc thiết lập một thuộc tính trên một đối tượng JavaScript. Đó là một hoạt động tương đối đơn giản.
Điều chậm ở đây là quá trình layout mà các trình duyệt phải thực hiện mỗi khi DOM thay đổi. Mỗi khi DOM thay đổi, trình duyệt cần phải tính toán lại CSS và thực hiện dựng lại (re-render) trang web. Đây là quá trình tốn thời gian.
Ngày nay, DOM Tree thường rất lớn, đặc biệt với sự phát triển mạnh mẽ của các trang web SPA (Single Page Application). Việc sửa đổi DOM Tree diễn ra liên tục và trên diện rộng.
Vấn đề với việc thao tác DOM trực tiếp
Xét một DOM được tạo bởi hàng nghìn thẻ div, việc xử lý các event như click, submit,… trở nên phức tạp. Cách xử lý event điển hình trong jQuery thường là:
- Tìm tất cả các node liên quan đến event.
- Cập nhật nó nếu cần thiết.
Điều này dẫn đến hai vấn đề chính:
- Khó quản lý: Việc chỉnh sửa một đoạn xử lý event mà không nắm được ngữ cảnh (context) đòi hỏi bạn phải tìm hiểu sâu trong code, tốn thời gian và tăng rủi ro.
- Không hiệu quả: Việc tìm kiếm tất cả các node liên quan đến event là không cần thiết. Thay vào đó, chỉ cần tìm node nào cần cập nhật sẽ hiệu quả hơn.
ReactJS mang đến giải pháp bằng cách cho phép định nghĩa các component có cấu trúc tương tự DOM Tree. ReactJS sẽ đảm nhiệm công việc xử lý ở tầng thấp hơn, thông qua HTML DOM API. Đây chính là cách Virtual DOM hoạt động.
Virtual DOM là gì?
Virtual DOM không phải do React tạo ra, nhưng React sử dụng nó để cung cấp một giải pháp hiệu quả.
Nói một cách tổng quát, Virtual DOM là một định dạng dữ liệu JavaScript nhẹ, được dùng để thể hiện nội dung của DOM tại một thời điểm nhất định. Nó có tất cả các thuộc tính giống như DOM, nhưng không có khả năng tương tác trực tiếp lên màn hình như DOM.
Bạn có thể hình dung, nếu ở DOM có thẻ div và các thẻ p bên trong, ReactJS sử dụng Virtual DOM bằng cách tạo ra các object React.div và React.p. Khi tương tác, chúng ta sẽ tương tác qua các object này một cách nhanh chóng, mà không cần tác động trực tiếp tới DOM hay DOM API.
Đây là lý do tại sao cú pháp JSX (JavaScript XML) trong code ReactJS trông giống như code HTML thuần túy.
var CommentBox = React.createClass({
render: function() {
return (
Syntax like HTML
);
}
});
Trong hầu hết các trường hợp, khi bạn có đoạn code HTML và muốn chuyển nó vào ReactJS, tất cả những gì bạn cần làm là:
- Gõ code HTML trong
render. - Thay thế
classthànhclassName.
Virtual DOM sử dụng các thuộc tính key và ref mà DOM không có. Virtual DOM cũng được tạo mới sau mỗi lần render lại.
Snapshots & Diffing: Bí quyết của Virtual DOM
Sự đặc biệt của Virtual DOM nằm ở cơ chế Snapshots (ảnh chụp nhanh) và Diffing (so sánh).
React lấy một snapshot của Virtual DOM (bản ghi trạng thái) ngay trước khi áp dụng bất kỳ bản cập nhật nào. Sau đó, nó sử dụng snapshot này để so sánh với Virtual DOM đã được cập nhật trước khi thực hiện các thay đổi.
So sánh Virtual DOM
Khi cập nhật được cấp cho Virtual DOM, React sử dụng thuật toán Diffing để so sánh và đối chiếu, xác định vị trí cần cập nhật, và chỉ cập nhật những elements liên quan, bỏ qua những elements không thay đổi.
Thuật toán Diffing
Chỉ những đối tượng đã thay đổi mới được cập nhật trên DOM, và những thay đổi này sẽ làm cho màn hình hiển thị thay đổi.
Cập nhật DOM thực
Việc tách biệt logic liên quan đến rendering ra khỏi DOM cho phép React chạy được trên nhiều môi trường khác nhau thay vì chỉ trình duyệt (React Native hoặc SSR – Server-Side Rendering). Virtual DOM thực chất chỉ là một JavaScript object, do đó nó có thể chạy ở bất kỳ môi trường nào có thể chạy JavaScript. Ví dụ: SSR sử dụng NodeJS hoặc embedded JavaScript khi xây dựng các ứng dụng native cho Web và Mobile.
Công việc của chúng ta là thay đổi generation algorithm (thuật toán tạo) cho từng môi trường cụ thể nhằm thu được các output mong muốn.
Virtual DOM cho phép tính toán các thay đổi (chỉ bằng JavaScript) và áp dụng đồng thời các thay đổi đó lên Actual DOM khi cần thiết. Phương pháp này hiệu quả hơn so với việc truy cập trực tiếp Actual DOM element (sử dụng jQuery) và tính toán các thay đổi trên đó.
Virtual DOM có thực sự nhanh hơn DOM?
Bản thân Virtual DOM rất nhanh. Nó có thể tìm kiếm, cập nhật và xóa bỏ các elements từ Virtual DOM Tree một cách nhanh chóng. Tuy nhiên, các thao tác tương tự trên DOM cũng rất nhanh. Vấn đề nằm ở việc bố cục và thể hiện các elements của DOM, quá trình này chậm hơn.
Do đó, React Virtual DOM không nhanh hơn DOM.
Một lợi ích khi sử dụng React là chúng ta có thể kiểm soát việc re-render của các component bằng cách sử dụng phương thức shouldComponentUpdate và setState.
Virtual DOM có làm tăng performance cho ứng dụng?
Hiệu năng của Virtual DOM
Trong thời kỳ đầu, React từng tuyên bố rằng Virtual DOM sẽ giúp tăng performance. Tuy nhiên, hiện tại họ không còn khẳng định điều này mà chỉ nhấn mạnh sự tiện lợi cho nhà phát triển.
Một số người cho rằng Virtual DOM giúp cập nhật DOM nhanh chóng, nhưng điều này không khả thi về mặt kỹ thuật. Cập nhật DOM phải được tối ưu hóa trong mã gốc của trình duyệt, không có “phép màu” nào có thể giải quyết vấn đề này.
Bài viết này nhằm làm rõ mục đích sử dụng của Virtual DOM trong React. Lợi ích của nó là điều dễ nhận thấy. Những vấn đề được đề cập trong bài viết được tổng hợp và cảm thấy khá hợp lý, chứ không phải là một khẳng định chính thống.
Tham khảo:
(Cần bổ sung các nguồn tham khảo uy tín về Virtual DOM và ReactJS)
