Defer JavaScript là gì? Hướng dẫn chi tiết cách sử dụng defer để tối ưu tốc độ tải trang

defer javascript là gì

Khi phát triển web, việc tối ưu hiệu suất tải trang luôn là ưu tiên hàng đầu. Một trong những kỹ thuật quan trọng giúp cải thiện tốc độ đó là sử dụng thuộc tính defer cho thẻ script. Vậy defer javascript là gì và nó hoạt động ra sao? Bài viết này sẽ giải thích chi tiết từ khái niệm cơ bản, cách hoạt động, so sánh với các thuộc tính khác như async, đến những ứng dụng thực tế và sai lầm thường gặp. Bạn sẽ hiểu rõ cách defer giúp trình duyệt tải JavaScript mà không chặn quá trình render HTML, từ đó cải thiện đáng kể trải nghiệm người dùng và điểm số Core Web Vitals.

Defer JavaScript là gì? Giải thích bản chất và cách hoạt động

defer javascript là gì - Hình 5

Defer là một thuộc tính Boolean trong thẻ <script> của HTML. Khi được thêm vào, nó yêu cầu trình duyệt tải file JavaScript song song với quá trình phân tích (parse) HTML, nhưng chỉ thực thi script sau khi toàn bộ tài liệu HTML đã được phân tích xong. Nói cách khác, defer cho phép HTML được hiển thị trước, trong khi trình duyệt vẫn tải JavaScript ở nền. Khi DOM đã sẵn sàng, các script deferred sẽ được thực thi theo đúng thứ tự xuất hiện trong code.

Điểm mấu chốt của defer nằm ở hai hành vi: tải không chặn (non-blocking) và thực thi trì hoãn. Không giống như script thông thường (không có thuộc tính) vốn chặn quá trình parse HTML ngay khi gặp thẻ script, defer giúp trình duyệt tiếp tục đọc và dựng DOM mà không bị gián đoạn. Việc thực thi chỉ diễn ra sau khi HTML hoàn tất, đảm bảo rằng script có thể truy cập đầy đủ các phần tử trong DOM.

Cách trình duyệt xử lý thẻ script có thuộc tính defer

Khi trình duyệt gặp thẻ <script defer> trong quá trình parse HTML:

    • Trình duyệt bắt đầu tải file JavaScript xuống song song (asynchronous download) mà không dừng quá trình phân tích HTML.
    • Quá trình parse HTML tiếp tục bình thường cho đến khi gặp thẻ đóng </html>.
    • Khi HTML đã được phân tích hoàn toàn, trình duyệt sẽ thực thi tất cả các script deferred theo đúng thứ tự xuất hiện trong tài liệu.
    • Sự kiện DOMContentLoaded sẽ chỉ được kích hoạt sau khi tất cả script deferred đã thực thi xong.

Điều này có nghĩa là nếu bạn đặt nhiều script deferred, chúng sẽ được thực thi tuần tự, đảm bảo thứ tự phụ thuộc giữa các script. Ví dụ, nếu bạn có thư viện jQuery và script phụ thuộc vào jQuery, cả hai đều dùng defer thì jQuery sẽ chạy trước.

So sánh defer vs async vs script thường: Bảng đối chiếu chi tiết

defer javascript là gì - Hình 4

Để hiểu rõ hơn defer javascript là gì và khi nào nên dùng, cần phân biệt với hai loại script khác: script thường (không thuộc tính) và script có async. Mỗi loại có hành vi tải và thực thi khác nhau, ảnh hưởng trực tiếp đến hiệu suất và thứ tự thực thi.

Thuộc tính Cách tải (Download) Thời điểm thực thi Thứ tự thực thi Sự kiện DOMContentLoaded
Không có (script thường) Chặn parse HTML, tải đồng bộ Ngay sau khi tải xong, trước khi parse tiếp Theo thứ tự xuất hiện Chờ toàn bộ script thường tải và thực thi
async Tải song song, không chặn parse Ngay khi tải xong, bất kỳ lúc nào (có thể giữa lúc parse) Không đảm bảo thứ tự (script nào tải xong trước chạy trước) Không chờ async, có thể xảy ra trước hoặc sau
defer Tải song song, không chặn parse Sau khi parse HTML hoàn tất Đảm bảo thứ tự xuất hiện Chờ tất cả script deferred thực thi xong

Như bảng trên cho thấy, defer là lựa chọn an toàn nhất khi bạn cần đảm bảo DOM đã sẵn sàng và duy trì thứ tự thực thi. async phù hợp cho các script độc lập như phân tích, quảng cáo – nơi thứ tự không quan trọng. Script thường nên tránh trong hầu hết trường hợp vì nó chặn render.

Lợi ích của việc sử dụng defer trong JavaScript

defer javascript là gì - Hình 3

Việc áp dụng defer mang lại nhiều lợi ích thiết thực, đặc biệt trong bối cảnh tối ưu hóa hiệu suất web.

  • Cải thiện thời gian tải trang: Vì defer tải script song song, trang hiển thị nhanh hơn. Người dùng có thể thấy nội dung HTML ngay lập tức mà không phải chờ JavaScript tải và thực thi.
  • Không chặn render: Không giống script thường, defer không làm gián đoạn quá trình dựng DOM. Điều này giúp First Contentful Paint (FCP) và Largest Contentful Paint (LCP) được cải thiện rõ rệt.
  • Đảm bảo thứ tự thực thi: Đối với các script có phụ thuộc lẫn nhau, defer giữ đúng thứ tự. Ví dụ, một thư viện và một script sử dụng thư viện đó có thể được xếp theo thứ tự và deferred, chúng sẽ chạy đúng tuần tự.
  • Không làm hỏng cấu trúc DOM: Vì script chạy sau khi DOM hoàn chỉnh, bạn không cần bọc code trong sự kiện DOMContentLoaded. Các thao tác truy cập phần tử HTML luôn an toàn.
  • Tối ưu Core Web Vitals: Bằng cách giảm thời gian chặn render, defer tích cực tác động đến các chỉ số như TBT (Total Blocking Time) và INP (Interaction to Next Paint).

Ứng dụng thực tế: Khi nào nên dùng defer?

Không phải mọi script đều cần defer.

Nên dùng defer khi:

  • Script thao tác với DOM: Các thư viện UI framework (React, Vue, Angular – nhưng thường được bundle), thư viện jQuery, hoặc script tùy chỉnh cần truy cập các phần tử HTML. Dùng defer đảm bảo DOM tồn tại khi script chạy.
  • Script phụ thuộc thứ tự: Ví dụ, một script analytics tải sau library quản lý tags. Defer duy trì thứ tự chính xác.
  • Script không cần chạy ngay lập tức: Các tính năng không quan trọng cho lần hiển thị đầu tiên, như chatbot, công cụ chia sẻ mạng xã hội, script tương tác phụ.
  • Tối ưu hóa cho SEO: Google sử dụng thời gian tải trang như một yếu tố xếp hạng. Defer giúp trang load nhanh hơn, cải thiện thứ hạng.

Không nên dùng defer khi:

  • Script cần thực thi ngay lập tức: Ví dụ, script chặn hiển thị quảng cáo hoặc script chặn copy nội dung. Các script này cần chạy trước khi HTML được hiển thị, nên phải dùng script thường (không thuộc tính).
  • Script độc lập, không cần thứ tự: Các script phân tích như Google Analytics, Facebook Pixel, hoặc script quảng cáo – nên dùng async để tải nhanh mà không chặn.
  • Script có kích thước rất nhỏ: Nếu script chỉ vài dòng code, việc defer có thể không mang lại lợi ích tải song song rõ rệt. Tuy nhiên, vẫn có thể dùng defer để duy trì sự nhất quán.

Cách sử dụng defer: Hướng dẫn từng bước với ví dụ cụ thể

defer javascript là gì - Hình 2

Áp dụng defer rất đơn giản. Bạn chỉ cần thêm từ khóa “defer” vào thẻ mở của thẻ script.

Bước 1: Viết thẻ script với thuộc tính defer

Giả sử bạn có file script.js và muốn nó được tải song song, thực thi sau khi HTML sẵn sàng. Code HTML sẽ như sau:

<script src="script.js" defer></script>

Lưu ý: Thuộc tính defer chỉ có tác dụng khi thẻ script có thuộc tính src (tức là file ngoài). Đối với script inline (viết trực tiếp trong HTML), defer sẽ bị bỏ qua.

Bước 2: Đặt thẻ script trong phần head hoặc cuối body?

Defer cho phép bạn đặt thẻ script trong phần mà không gây ảnh hưởng xấu. Đây là một lợi thế lớn: bạn không cần phải dồn hết script xuống cuối body như cách làm truyền thống. Tuy nhiên, thói quen đặt script cuối body vẫn phổ biến. Với defer, đặt trong head sẽ giúp trình duyệt phát hiện script sớm hơn, bắt đầu tải sớm hơn, từ đó giảm thời gian thực thi tổng thể.

Bước 3: Kiểm tra thứ tự script

Nếu có nhiều script deferred, hãy đảm bảo thứ tự trong HTML đúng với thứ tự phụ thuộc. Ví dụ:

<script src="jquery.js" defer></script>
<script src="plugin.js" defer></script>
<script src="main.js" defer></script>

jQuery sẽ tải và thực thi trước plugin, plugin chạy trước main. Tất cả diễn ra sau khi DOM sẵn sàng.

Ví dụ thực tế: So sánh trang web có và không có defer

Giả sử bạn có một trang HTML với 3 script nặng (mỗi file 200KB). Trường hợp không có defer: mỗi script chặn parse, tổng thời gian chặn có thể lên đến 1,5 giây. Với defer: cả 3 script tải song song trong nền, HTML hiển thị ngay, script thực thi chỉ mất 0,3 giây sau khi DOM ready. Kết quả là LCP giảm từ 3,5 giây xuống còn 1,8 giây.

Sai lầm thường gặp khi dùng defer và cách tránh

Dù defer rất hữu ích, nhưng nếu sử dụng không đúng cách, nó có thể gây ra lỗi hoặc phản tác dụng.

  • Dùng defer cho script inline: Thuộc tính defer không hoạt động khi script được viết trực tiếp trong thẻ <script>...</script> (không có src). Trình duyệt sẽ bỏ qua defer. Giải pháp: chuyển script inline ra file ngoài hoặc dùng module type=”module”.
  • Kết hợp defer và async trên cùng một thẻ: Hai thuộc tính này mâu thuẫn nhau. Nếu bạn thêm cả defer và async, async sẽ được ưu tiên trong hầu hết trình duyệt (có ngoại lệ). Luôn chỉ dùng một trong hai.
  • Đặt script deferred không đúng thứ tự: Nếu script A phụ thuộc script B nhưng bạn đặt A trước B, thì khi thực thi deferred, A sẽ chạy trước và có thể lỗi vì B chưa được nạp. Giải pháp: sắp xếp thẻ script theo đúng thứ tự phụ thuộc.
  • Lạm dụng defer cho mọi script: Script quảng cáo hoặc script theo dõi thường cần chạy càng sớm càng tốt. Defer có thể làm chậm quá trình khởi tạo của chúng, ảnh hưởng đến doanh thu. Dùng async cho các script này.
  • Không kiểm tra tương thích: Defer được hỗ trợ bởi tất cả trình duyệt hiện đại, nhưng các trình duyệt cũ như IE9 trở về trước có thể bỏ qua defer. Nếu bạn cần hỗ trợ rộng rãi, hãy cân nhắc fallback.

Lưu ý quan trọng khi tối ưu JavaScript với defer

defer javascript là gì - Hình 1

Để tận dụng tối đa sức mạnh của defer, hãy ghi nhớ những điểm sau:

  • Kết hợp với kỹ thuật lazy loading: Những script không cần thiết ngay lần tải đầu (ví dụ: modal, carousel) có thể được tải deferred kết hợp với dynamic import để giảm tải ban đầu.
  • Sử dụng type=”module” khi có thể: Các script module (ES6) mặc định hoạt động giống defer (tải song song, thực thi sau parse) và hỗ trợ import/export. Đây là giải pháp hiện đại thay thế defer.
  • Giảm kích thước script: Dù dùng defer, script càng nhỏ thì thời gian tải và thực thi càng ít. Nén file bằng minify, tree-shaking và compression (gzip, brotli) là cần thiết.
  • Theo dõi hiệu suất thực tế: Sử dụng Lighthouse, WebPageTest hoặc Chrome DevTools để đo lường tác động của defer. So sánh trước và sau để đảm bảo defer thực sự có lợi.
  • Tránh phụ thuộc vào sự kiện DOMContentLoaded: Với defer,

    Có. Defer cải thiện tốc độ tải trang, giảm thời gian chặn render, từ đó tăng điểm số Core Web Vitals. Google sử dụng các chỉ số này làm yếu tố xếp hạng, nên defer gián tiếp hỗ trợ SEO.

    Sự khác biệt giữa defer và async là gì?

    Defer thực thi script sau khi parse HTML xong và đảm bảo thứ tự. Async thực thi script ngay khi tải xong, không đảm bảo thứ tự và có thể chạy giữa lúc parse. Dùng defer khi cần thứ tự, dùng async khi script độc lập.

    Có thể dùng defer cho script inline không?

    Không. Thuộc tính defer chỉ hoạt động với file script bên ngoài (có thuộc tính src). Script inline sẽ bỏ qua defer. Để đạt hiệu ứng tương tự, hãy chuyển script inline thành file riêng hoặc sử dụng type=”module”.

    Defer có hoạt động trên tất cả trình duyệt không?

    Defer được hỗ trợ từ Internet Explorer 10 trở lên và mọi trình duyệt hiện đại (Chrome, Firefox, Safari, Edge). Trên các trình duyệt quá cũ (IE9-), defer bị bỏ qua, và script sẽ tải theo cách thông thường (chặn render).

    Nên đặt thẻ script defer ở đâu trong HTML?

    Đúng. DOMContentLoaded sẽ không được kích hoạt cho đến khi tất cả script deferred thực thi xong. Nếu bạn có nhiều script deferred nặng, thời gian kích hoạt sự kiện này có thể bị trì hoãn. Nhưng vì HTML đã hiển thị, người dùng thường không thấy sự chậm trễ.

    Kết luận

    Defer javascript là gì – đó là một thuộc tính đơn giản nhưng mạnh mẽ giúp tối ưu hiệu suất tải trang. Bằng cách cho phép script tải song song và thực thi sau khi HTML hoàn tất, defer loại bỏ tình trạng chặn render, cải thiện thời gian hiển thị nội dung và trải nghiệm người dùng. Khác với async, defer vẫn giữ thứ tự thực thi, phù hợp cho các script phụ thuộc lẫn nhau. Việc áp dụng defer đúng cách, kết hợp với các kỹ thuật tối ưu khác, sẽ giúp trang web của bạn đạt điểm cao trong Core Web Vitals và cải thiện thứ hạng tìm kiếm. Hãy bắt đầu bằng cách thay thế các script chặn render bằng deferred, và bạn sẽ thấy sự khác biệt ngay trong lần kiểm tra hiệu suất tiếp theo.

  • Bài viết cùng chủ đề:

    Để lại một bình luận

    Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *