Back to Explore
Khi hai thẻ ES module cùng trỏ về một nguồn: Bài học về cơ chế tải script trong trình duyệt

Khi hai thẻ ES module cùng trỏ về một nguồn: Bài học về cơ chế tải script trong trình duyệt

Bạn đã bao giờ gặp tình huống khai báo hai thẻ script ES module với cùng một đường dẫn src nhưng chỉ có một module thực thi? Đây không phải là lỗi trình duyệt, mà là cách cơ chế module của JavaScript vận hành. Hãy cùng phân tích sâu về cơ chế deduplication và cách tối ưu hóa việc quản lý tài nguyên trong các ứng dụng web hiện đại.

Website
Upvote this postSign in to upvote this article.

Bài viết được dịch và tổng hợp từ tin tức gốc. Bạn có thể đọc bài viết gốc bằng tiếng Anh tại đây.

Điểm tin nhanh:

  • Trình duyệt áp dụng cơ chế deduplication cho các ES module có cùng URL để tránh thực thi trùng lặp.
  • Việc khai báo nhiều thẻ script module với cùng src chỉ kích hoạt quá trình tải và thực thi module đó đúng một lần duy nhất.
  • Hiểu rõ cơ chế này giúp lập trình viên tối ưu hóa hiệu năng và tránh các lỗi logic tiềm ẩn khi quản lý state trong ứng dụng.

Trong thế giới phát triển web, chúng ta thường tin rằng mỗi thẻ script trong HTML sẽ tương ứng với một hành động thực thi mã nguồn. Tuy nhiên, khi chuyển dịch sang kỷ nguyên của ES modules (ESM), trình duyệt đã thay đổi cách tiếp cận để đảm bảo tính nhất quán và hiệu năng. Nếu bạn từng loay hoay debug vì một đoạn mã khởi tạo quan trọng không chạy lần thứ hai như mong đợi, rất có thể bạn đã rơi vào cơ chế quản lý module của trình duyệt. Đây là một trong những kiến thức nền tảng mà bất kỳ kỹ sư nào cũng cần nắm vững để tránh việc tối ưu hóa quy trình kiểm thử ứng dụng Web với SolonTest và HttpTester trở nên vô nghĩa do các lỗi runtime không mong muốn.

Cơ chế thực thi ES Module trong trình duyệt

Khác với các thẻ script truyền thống (classic scripts), ES modules được thiết kế để tuân thủ nguyên tắc singleton. Khi trình duyệt gặp một thẻ <script type="module" src="...">, nó sẽ thực hiện các bước sau:

  1. Kiểm tra URL của module.
  2. Nếu module chưa từng được tải, trình duyệt sẽ fetch và thực thi nó.
  3. Nếu module đã được tải (dựa trên URL), trình duyệt sẽ bỏ qua việc thực thi lại.

Điều này đảm bảo rằng các side-effect (như khởi tạo biến toàn cục, đăng ký event listener) chỉ xảy ra một lần duy nhất, giúp hệ thống ổn định hơn. Nếu bạn đang xây dựng các hệ thống phức tạp, việc nắm vững cách quản lý tài nguyên này cũng quan trọng tương đương với việc xây dựng hệ thống tri thức AI bền vững: Kết hợp Markdown và Git cho quản lý dữ liệu.

Ảnh bìa bài viết

Phân tích hành vi thực thi

Hãy xem xét bảng so sánh dưới đây để thấy sự khác biệt giữa các loại script:

Đặc điểm Classic Script ES Module
Thực thi nhiều lần Có (nếu khai báo nhiều thẻ) Không (deduplication theo URL)
Scope Global Module scope
Mặc định Sync/Async tùy thuộc thuộc tính Defer (chờ DOMContentLoaded)

Mẹo hay: Nếu bạn thực sự cần chạy một đoạn mã nhiều lần, hãy sử dụng các hàm export thay vì dựa vào side-effect của việc load file. Điều này giúp code của bạn tường minh và dễ kiểm thử hơn, tương tự như cách chúng ta tối ưu hóa quy trình giám sát AI: Tự động hóa logging API OpenAI và Anthropic chỉ với một dòng code.

Sơ đồ luồng xử lý của trình duyệt

Khi trình duyệt gặp thẻ script module, luồng xử lý diễn ra như sau:

[Thẻ Script] ---> [Check Cache/URL] ---> [Đã tải?] ---> (Có) ---> [Bỏ qua]
---> (Không) ---> [Fetch & Execute]

Đánh giá & Lời khuyên Thực tiễn

Từ góc độ của một Senior Tech Lead, cơ chế này là một tính năng, không phải là lỗi. Nó giúp ngăn chặn việc khởi tạo trùng lặp các thư viện nặng hoặc các đối tượng singleton. Tuy nhiên, rủi ro nằm ở việc lập trình viên phụ thuộc vào việc "tải lại" để reset state. Khi làm việc với các hệ thống lớn, hãy đảm bảo rằng kiến trúc của bạn không dựa vào việc load lại script để khởi tạo lại dữ liệu. Nếu bạn đang đối mặt với các vấn đề về kiến trúc, hãy tham khảo thêm về Architecture Decision Records: Bí quyết ghi chép kiến trúc giúp team không bao giờ lạc lối.

Lưu ý: Hãy cẩn thận với các query parameter trong URL. Trình duyệt coi script.jsscript.js?v=1 là hai module khác nhau. Điều này có thể dẫn đến việc tải lại module không mong muốn nếu bạn không quản lý versioning cẩn thận.

Câu hỏi thường gặp (FAQ)

Tại sao trình duyệt lại chặn việc thực thi lại module?

Để đảm bảo tính nhất quán của trạng thái module. Nếu một module chứa các biến trạng thái, việc thực thi lại sẽ làm hỏng các logic phụ thuộc vào trạng thái đó.

Làm sao để buộc module chạy lại?

Bạn không nên làm vậy. Thay vào đó, hãy export một hàm khởi tạo từ module đó và gọi hàm đó bất cứ khi nào bạn cần reset hoặc chạy lại logic.

Cơ chế này có ảnh hưởng đến hiệu năng không?

Có, nó giúp tăng hiệu năng đáng kể bằng cách tránh việc fetch và parse lại cùng một file nhiều lần trong cùng một phiên làm việc.

Kết luận

Việc hiểu rõ cơ chế deduplication của ES modules là bước tiến quan trọng để làm chủ môi trường runtime của trình duyệt. Thay vì cố gắng chống lại cơ chế này, hãy thiết kế ứng dụng của bạn theo hướng module hóa và sử dụng các hàm export để kiểm soát luồng thực thi. Nếu bạn thấy bài viết này hữu ích, đừng quên theo dõi hi_dev để cập nhật những kiến thức công nghệ chuyên sâu nhất và tham gia thảo luận cùng cộng đồng lập trình viên chuyên nghiệp.

Discussion (0)

You need to log in to post comments. Log In

No comments yet. Start the discussion!