0
0
Lập trình
Flame Kris
Flame Krisbacodekiller

🚀 Khám Phá React Fiber: Hướng Dẫn Về Render Tăng Tiến & Đồng Thời ⚛️

Đăng vào 1 tháng trước

• 6 phút đọc

🌟 Giới thiệu

Khi tôi bắt đầu tìm hiểu về React Fiber, tôi có rất nhiều câu hỏi trong đầu:

  • Khi nào thì WIP (work-in-progress) Fiber được tạo ra?
  • Nếu trạng thái của một component con được cập nhật, tại sao React lại xây dựng lại từ component cha?
  • Điều gì xảy ra nếu một nửa công việc đã hoàn thành và React quyết định tạm dừng?
  • Có thể tồn tại nhiều WIP trees cùng một lúc không?

Bài viết này là một cơ sở kiến thức + câu chuyện về hành trình hiểu biết của tôi về Fiber. Tôi sẽ giải thích các khái niệm theo thứ tự đồng thời lồng ghép các câu hỏi mà đã thúc đẩy sự tò mò của tôi.


🧵 Lần Đầu Tiên — Khi Nào Fiber Được Tạo?

Khi bạn chạy:

javascript Copy
import { createRoot } from "react-dom/client";

createRoot(container).render(<App />);
  • React sẽ tạo ra một Root Fiber (HostRootFiber).
  • Từ root này, React xây dựng cây Fiber hiện tại (DOM mà ứng dụng của bạn hiển thị).
  • Đồng thời, mỗi khi một render được kích hoạt, React bắt đầu xây dựng một WIP Fiber tree (UI tiềm năng tiếp theo).

👉 Chỉ có một root Fiber tồn tại, nhưng nó có thể có hai nhánh:

  • current → cái đang được vẽ trên màn hình.
  • workInProgress → đang được xây dựng trong bộ nhớ cho lần vẽ tiếp theo.

🔄 Câu Chuyện WIP

Câu Hỏi Của Tôi:

Liệu React có xây dựng WIP sau mỗi commit không? Nếu có, làm thế nào mà nó biết được công việc đang chờ?

Câu Trả Lời:

  • Sau mỗi commit, WIP trở thành current mới.
  • Nếu có các cập nhật đang chờ trong khi đang render, React sẽ:
    • Tái sử dụng công việc WIP một phần (tiếp tục render).
    • Vứt bỏ WIP chưa hoàn thành và bắt đầu một WIP mới để có khả năng phản hồi tốt hơn.

💡 Ngay cả khi React vứt bỏ một WIP, các cập nhật của bạn không bị mất — chúng vẫn tồn tại trong hàng đợi cập nhật của Fiber hiện tại.


⏸️ Tạm Dừng, Tiếp Tục và Vứt Bỏ

React Fiber được xây dựng để hỗ trợ render có thể bị gián đoạn.

  • Nếu công việc mất quá nhiều thời gian, React sẽ yield (tạm dừng) để cho trình duyệt vẽ.
  • Trong khung hình tiếp theo, React có thể:
    • Tiếp tục WIP đó (tiếp tục từ nơi đã dừng).
    • Vứt bỏ WIP và xây dựng lại từ current (nếu có cập nhật ưu tiên cao hơn).

📌 Ví dụ:
Nếu bạn gõ vào <input />, React có thể vứt bỏ WIP chưa hoàn thành và xây dựng lại nhanh chóng để cảm giác gõ phím của bạn thật tức thì.


🌳 Hòa Giải Fiber Cha-Con

Câu Hỏi Của Tôi:

Nếu chỉ có trạng thái của child1 thay đổi, tại sao React lại duyệt từ root → parent → child1 → child2?

Câu Trả Lời:

Bởi vì hòa giải luôn bắt đầu từ parent của Fiber đã được cập nhật.

  • WIP Fiber của parent được xây dựng lại.
  • Các children được ghé thăm để quyết định:
    • Tái sử dụng Fiber hiện có (alternate).
    • Hoặc tạo mới WIP Fiber (nếu props/state đã thay đổi).

👉 Đây là lý do tại sao ngay cả các siblings (như child2) cũng có thể được duyệt qua, mặc dù không phải lúc nào cũng được xây dựng lại.


⚡ Giai Đoạn Commit — Cái Nhìn Mở Rộng

Ban đầu tôi nghĩ commit = “các thay đổi DOM được áp dụng”, nhưng nó phong phú hơn rất nhiều.

Commit có ba bước:

  1. Trước Khi Biến Đổi (snapshot phase)
  • getSnapshotBeforeUpdate
  • React chuẩn bị, ví dụ: đo vị trí cuộn.
  1. Giai Đoạn Biến Đổi (sync, không thể bị gián đoạn 🚨)
  • Các DOM nodes được tạo mới/cập nhật/xóa bỏ.
  • Ví dụ: chèn tất cả các child DOM nodes đã sẵn sàng trong một batch duy nhất để tối ưu hóa hiệu suất.
  1. Giai Đoạn Bố Trí (effects)
  • Chạy các hooks vòng đời:
    • componentDidMount
    • componentDidUpdate
  • Chạy lập lịch các hiệu ứng thụ động.

👉 Chỉ sau đó, trình duyệt sẽ vẽ với UI mới.


🎭 Nhiều WIP Trees

Đây là phần mà thực sự làm tôi ngạc nhiên:

  • React có thể chuẩn bị nhiều phiên bản UI cùng một lúc, nhưng chỉ ở giữa các đợt commit.
  • Tại bất kỳ thời điểm nào:
    • current → UI bạn thấy.
    • Một hoặc nhiều ứng viên WIP trong bộ nhớ.

⚖️ React chọn WIP chiến thắng vào thời điểm commit. Các WIP khác sẽ bị vứt bỏ.

📌 Quy trình Ví dụ:

  • Khung hình 1: WIP Slice A (30 Fibers). Yield.
  • Khung hình 2: Cập nhật ưu tiên cao hơn đến. React có thể bỏ qua Slice A.
  • Khung hình 3: Cây WIP mới được xây dựng, cam kết và vẽ.

Vì thế, đúng là — nhiều WIPs có thể tồn tại giữa các commit, nhưng chỉ một cái đến được DOM.


🧩 Render Tăng Tiến vs Render Đồng Thời

Tôi thường nhầm lẫn hai khái niệm này. Đây là sự khác biệt:

Render Tăng Tiến (Time Slicing)

  • Phân chia một render thành các khối nhỏ hơn (slices)
  • Mỗi slice được thực thi trong một khoảng thời gian ngắn (~5ms-16ms), sau đó nhường quyền điều khiển cho trình duyệt
  • Giữ cho UI phản hồi trong quá trình render nặng

Ví dụ:

javascript Copy
function App() {
  return (
    <>
      <HeavyList />   // mất nhiều thời gian để render
      <Sidebar />     // component nhẹ
    </>
  );
}
  • React sẽ render Sidebar trong slice đầu tiên, sau đó bắt đầu HeavyList
  • Nếu một người dùng nhấp vào một nút trong quá trình render HeavyList, React có thể nhường quyền để xử lý đầu vào ngay lập tức

Render Đồng Thời

  • React có thể chuẩn bị nhiều WIP trees đồng thời cho cùng một root
  • Cho phép các cập nhật ưu tiên cao ngắt quãng công việc ưu tiên thấp
  • Các WIP trees nằm trong bộ nhớ; chỉ một cái được cam kết với DOM

Ví dụ:

javascript Copy
<App>
  <SearchBar />      // ưu tiên cao
  <Feed />           // ưu tiên thấp, danh sách nặng
</App>
  • Gõ vào SearchBar sẽ kích hoạt một WIP tree ưu tiên cao
  • React có thể tạm dừng WIP của Feed, xây dựng cập nhật cho SearchBar đồng thời
  • WIP tree phù hợp nhất sẽ được cam kết trước

Sự Khác Biệt Chính:

  • Tăng Tiến = chia một render thành các khối
  • Đồng Thời = nhiều render khả thi đồng thời, React quyết định cái nào sẽ cam kết

🕒 So Sánh Thời Gian

Render Tăng Tiến

Copy
Gõ "a"
 -> Render Input Fiber
 -> Tạm dừng
 -> Render List Fiber (chia nhỏ)
 -> Cam kết tất cả

Render Đồng Thời

Copy
Gõ "a"
 -> Cam kết Input Fiber ngay lập tức
 -> Bắt đầu List Fiber trong nền

Gõ "ab" trước khi List hoàn thành
 -> Vứt bỏ List Fiber cũ
 -> Bắt đầu List Fiber mới với "ab"
 -> Cam kết khi sẵn sàng

Thời gian này cho thấy render tăng tiến chia công việc trong một render trong khi render đồng thời xử lý nhiều WIPs và các ngắt quãng ưu tiên cao.


📖 Những Điều Rút Ra Chính

  • Fiber cho phép render có thể bị gián đoạn, chia thời gian.
  • WIP luôn được xây dựng trong bộ nhớ; DOM chỉ được cập nhật trong commit.
  • React có thể tạm dừng, tiếp tục hoặc vứt bỏ WIP dựa trên ưu tiên.
  • Nhiều WIP trees có thể tồn tại giữa các đợt commit, nhưng chỉ một cái tồn tại.
  • Giai Đoạn Commit có 3 tiểu giai đoạn (trước khi biến đổi, biến đổi, bố trí).
  • Các hàng đợi cập nhật đảm bảo không có đầu vào nào của người dùng bị mất, ngay cả khi WIP bị vứt bỏ.

✍️ Tác Giả

👨‍💻 Yogesh Bamanier
🔗 LinkedIn

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