Bạn đã nghe React, Vue dùng Virtual DOM và thực sự thì nó rất nhanh, nhanh hơn cả DOM thật. Nhưng bạn chả hiểu Virtual DOM là cái gì và nó có ngon như lời đồn không. Bài viết hôm nay mình sẽ cùng các bạn đào sâu tìm hiểu Virtual DOM là gì cùng các nhận định liên quan đến Virtual DOM.

1. Đầu tiên phải biết DOM là gì?

DOM là viết tắt của Document Object Model (Mô hình Đối tượng Tài liệu) dùng để truy xuất các tài liệu dạng HTML và XML. DOM đại diện cho một tài liệu như là một cây cấu trúc dữ liệu. Còn node thì đại diện cho một phần tử trong DOM.

Ví dụ đoạn code HTML dưới đây sẽ mô tả cách trình duyệt hoạt động.

<div>
  <h1>Bài đồng dao</h1>
  Năm mới năm me
  <!-- TODO: Hoàn thành bài đồng dao -->
</div>

Khi đọc đoạn code này, trình duyệt sẽ xây dựng cấu trúc dạng cây (DOM tree) bao gồm các “DOM node” để giúp quản lí mọi thứ, tương tự như việc bạn xây dựng một cây gia phả để giữ thông tin về mọi người trong dòng họ vậy.

Cấu trúc cây của đoạn HTML trên sẽ giống như sau:

DOM tree

Mỗi phần tử trên DOM tree là một node. Mỗi text là một node. Ngay cả comment cũng là node! Một node đơn giản chỉ là một “mảnh” trên trang web. Và cũng tương tự như trong một cây gia phả, mỗi node có thể có các node con (nghĩa là một mảnh có thể chứa các mảnh khác).

Nếu muốn thay đổi giá trị các thẻ HTML, bạn không cần vào thẳng file HTML thay đổi lại mà chỉ cần thao tác trên DOM. Các phương thức DOM cho phép chúng ta truy cập đến cây cấu trúc và thay đổi cấu trúc, dữ liệu, style, nội dung của document.

Thời nay, các trang web có thể chứa đến hàng trăm ngàn các node khác nhau. Việc tìm kiếm và cập nhật lại DOM là một sự khó khăn. Chắc hẳn bạn không thể cứ document.getElementByClass() mãi để tìm từng node rồi tạo-xóa được, vì như vậy code sẽ phình rất to và tốc độ từ đó cũng chậm theo.

Đó chính là vấn đề khi thao tác  với DOM thật. Và thế là người ta tạo ra Virtual DOM để giải quyết vấn đề này. Đại diện nổi tiếng nhất cho Virtual DOMReactVue. Nhưng Virtual DOM không phải là giải pháp duy nhất, điển hình là ta có Incremetal DOM được dùng ở Angular, hay thao tác trực tiếp với DOM thậtSvetle.

2. Virtual DOM là gì?

Virtual DOM (VDOM hay DOM ảo) , là cách thể hiện DOM thật của một trang web dưới dạng các Javascript object. Khi thay đổi state của app thì VDOM sẽ được cập nhật lại và so sánh với VDOM cũ (VDOM cũ được đồng bộ hóa với DOM thật trước đó) bằng thuật toán gọi là diffing hay change detection để tìm ra những node cần thay đổi. Cuối cùng nó sẽ cập nhật những node đó trên DOM thật.

Ví dụ chúng ta muốn có một HTML như thế này

<div class="App">
    <h1>Simple vDOM</h1>
    <ul>
        <li>Hello</li>
        <li>Vietnam</li>
    </ul>
</div>

Thì khi biểu diễn trên VDOM thì sẽ có dạng object tổng thể tương tự như thế này.

const vDOM = {
  nodeName: 'div',
  attributes: 'app',
  children: [
    {
      nodeName: 'h1',
      attributes: null,
      children: ['Simple vDOM']
    },
    {
      nodeName: 'ul',
      attributes: null,
      children: [
        {
          nodeName: 'li',
          attributes: null,
          children: ['Hello']
        },
        {
          nodeName: 'li',
          attributes: null,
          children: ['Vietnam']
        }
      ]
    }
  ]
}

Và từ VDOM này, để render ra DOM thật thì ta dùng các DOM API của browser. Nếu không có các DOM API của browser thì chẳng thể nào mà tương tác với DOM thật ở client được.

document.createElement()
document.createTextNode()
document.appendChild()

Trên đây là cách thức hoạt động của Virtual DOM cũng như là React, Vue. Bây giờ mình sẽ giải thích một số lời đồn về Virtual DOM 😎

Virtual DOM nhanh hơn DOM thật

Đây thực sự là một lời PR quá đà, nó bắt nguồn từ JSConfEU năm 2013. Trong Rethinking Best Practices, Pete Hunt có nói về React như sau

This is actually extremely fast, primarily because most DOM operations tend to be slow. There’s been a lot of performance work on the DOM, but most DOM operations tend to drop frames

Screenshot from at JSConfEU 2013

Screenshot from at JSConfEU 2013

Thao tác trên VDOM nhanh, mình tin là nhanh hơn DOM thật, vì thay đổi thuộc tính của object kiểu gì cũng nhanh hơn thay đổi một node trên DOM thật. Nhưng mà khoan! Bạn định chỉ thao tác trên VDOM không thôi à, không render ra DOM thật à!

Khi nói về Virtual DOM thì phải nhìn nhận toàn bộ quá từ quá trình từ thao tác trên VDOM rồi đến lúc render ra DOM thật. Theo như chúng ta phân tích thì tiến trình VDOM được thêm vào giữa tiến trình xử lý với DOM thật. Rõ ràng nó mất thêm một giai đoạn xử lý VDOM, dùng thuật toán so sánh với VDOM cũ (tùy vào thuật toán mà chỗ này tốn khá nhiều performance) rồi mới render ra DOM thật.

Chỉ có một cách VDOM nhanh hơn DOM thật là nó so sánh với những Framework kém hiệu quả ( quay trở về 2013 ta có Jquery hay không dùng framework), hoặc render toàn bộ web ngu ngốc như thế này.

onEveryStateChange(() => {
  document.body.innerHTML = renderMyApp();
});

Vậy nên theo lý thuyết DOM thật nhanh hơn Virtual DOM! Bây giờ chúng ta có một Framework bỏ qua Virtual DOM, tối ưu được việc thao tác trực tiếp với DOM thật, đó là Svelte. Svelte đang phát triển rất nhanh, được PR là vô đối về mặt hiệu suất và khá triển vọng trong tương lai.

Vậy thì Virtual DOM chậm?

Không thực sự chính xác cho lắm. Mình nghĩ là nó đủ nhanh với tác vụ web ngày nay, nhưng với một số lưu ý là bạn phải hiểu cách hoạt động Framework của bạn.

Theo như lời hứa của React thì bạn có thể re-render app của bạn mỗi khi state thay đổi mà không cần lo lắng về hiệu suất. Nhưng thực tế thì đời không như mơ, bạn phải dùng thêm React.memo, useMemo, useReducer, shouldComponentUpdate … để hạn chế quá trình tính toán và render dư thừa 😡

Tại sao các một số framework hiện này còn dùng Virtual DOM?

Theo mình thì Virtual DOM được giới thiệu từ 2013 và lúc đó chưa có giải pháp nào nhanh, tiện lợi hơn Virtual DOM. Bạn chỉ cần tập trung phát triển App mà không cần quan tâm phải DOM chỗ nãy, DOM chỗ kia. Điều này nghĩa là code ít bug hơn, bạn có nhiều thời gian để sáng tạo hơn. Và cứ thế nó cứ phát triển, càng ngày người ta càng tối ưu thuật toán diffing để cho nó hiệu quả hơn. Đến bây giờ có thể cho là nó đủ tốt.

3. Tóm lại

Bài viết này mình muốn bạn hiểu rõ hơn về Virtual DOM là gì. Nó hoạt động như thế nào, và làm rõ một số nhận định liên quan đến Virtual DOM mà bạn nghe được ngoài kia. Đây là bài viết đầu tiên trong series đào sâu các framework của mình, nếu có gì thiếu xót các bạn có thể góp ý để các bài viết sau được tốt hơn. Nhớ like fanpage để đón chờ các bài viết chuyên sâu tiếp theo nhé :mrgreen:

Tham khảo:
https://vi.vuejs.org/v2/guide/render-function.html#Node-tree-va-virtual-DOM

https://svelte.dev/blog/virtual-dom-is-pure-overhead