Tối ưu hóa tốc độ tải trang là một cuộc chiến không hồi kết, và JavaScript thường là một trong những thủ phạm chính gây ra tình trạng chậm trễ. Việc các script chặn hiển thị (render-blocking) có thể khiến người dùng phải nhìn vào một trang trắng trong vài giây, làm tăng tỷ lệ thoát và ảnh hưởng tiêu cực đến thứ hạng SEO. Tại V4SEO, chúng tôi nhận thấy rằng việc hiểu rõ và áp dụng đúng các thuộc tính tải script là một trong những kỹ thuật tối ưu on-page mang lại hiệu quả cao nhất. Vậy async script là gì và làm thế nào để sử dụng nó cùng với defer để giải phóng tiềm năng tốc độ của website? Bài viết này sẽ cung cấp một hướng dẫn trực quan, từ định nghĩa cơ bản đến các kỹ thuật khắc phục sự cố nâng cao.
Tổng quan về tải script trong html: tại sao cần async và defer?
Để hiểu vai trò của async và defer, trước tiên cần nắm được cách trình duyệt xử lý một trang web thông thường. Quá trình này diễn ra tuần tự từ trên xuống dưới, và khi gặp một thẻ <script>, nó sẽ gây ra một vấn đề nghiêm trọng.
Vấn đề chặn hiển thị (render blocking) của script truyền thống
Khi trình duyệt phân tích (parsing) mã HTML và gặp một thẻ <script> không có thuộc tính async hay defer, nó sẽ ngay lập tức dừng việc phân tích HTML. Tiếp theo, trình duyệt phải tải về toàn bộ file script đó và thực thi nó. Chỉ sau khi script đã thực thi xong, trình duyệt mới tiếp tục phân-tích-phần-còn-lại của tài liệu HTML. Quá trình này được gọi là "render-blocking" hay chặn hiển thị, vì nó ngăn cản việc hiển thị nội dung trang cho đến khi script được xử lý xong, gây ra trải nghiệm người dùng kém.

Cơ chế hoạt động của trình duyệt khi tải và thực thi javascript
Cơ chế mặc định này đảm bảo rằng script có thể tương tác với DOM ngay khi nó được thực thi, nhưng phải trả giá bằng hiệu suất tải trang. Các thuộc tính async và defer ra đời để thay đổi hành vi mặc định này, cho phép trình duyệt tải script một cách thông minh hơn mà không cần phải tạm dừng hoàn toàn việc xây dựng trang. Việc này giúp cải thiện đáng kể thời gian tải trang nhận thức được và các chỉ số Core Web Vitals.
Thuộc tính async của thẻ <script>: tải không đồng bộ là gì?
Thuộc tính async là một thuộc tính boolean cho thẻ <script>, báo cho trình duyệt rằng script có thể được tải về song song với quá trình phân tích HTML và thực thi ngay khi tải xong.

Định nghĩa và nguyên lý hoạt động của async
Khi trình duyệt gặp <script async src="…">, nó sẽ bắt đầu tải script về mà không dừng việc phân tích HTML. Quá trình tải script và phân tích HTML diễn ra đồng thời (không đồng bộ). Tuy nhiên, ngay khi script được tải về xong, trình duyệt sẽ tạm dừng việc phân tích HTML để thực thi script đó. Sau khi thực thi xong, nó mới tiếp tục phân tích phần còn lại. Điều này có nghĩa là async vẫn có thể chặn hiển thị trong một khoảng thời gian ngắn lúc thực thi.
Ví dụ mã nguồn chi tiết và kết quả mong đợi
Xét đoạn mã sau, script1.js và script2.js sẽ được tải song song. Script nào tải xong trước sẽ thực thi trước, không đảm bảo thứ tự.
<script async src="script1.js"></script>
<script async src="script2.js"></script>
<p>Nội dung trang web…</p>
Kết quả là trình duyệt sẽ hiển thị đoạn <p> gần như ngay lập tức vì việc phân tích HTML không bị chặn trong quá trình tải script. Tuy nhiên, thứ tự thực thi của script1.js và script2.js là không thể đoán trước.
Ưu điểm và nhược điểm của async
Ưu điểm: Không chặn việc phân tích HTML trong lúc tải, giúp trang hiển thị nhanh hơn. Rất hiệu quả cho các script độc lập, không phụ thuộc vào DOM hoặc các script khác.
Nhược điểm: Chặn việc phân tích HTML trong lúc thực thi. Không đảm bảo thứ tự thực thi, gây ra lỗi nếu các script phụ thuộc lẫn nhau. Không nên dùng cho các script cần truy cập hoặc thay đổi DOM ngay khi tải.
Khi nào nên sử dụng async? (với các script độc lập, không phụ thuộc)
Sử dụng async là lựa chọn lý tưởng cho các script của bên thứ ba không quan trọng đối với việc hiển thị nội dung ban đầu. Ví dụ điển hình là các script phân tích (analytics), script quảng cáo, hoặc các widget mạng xã hội. Những script này có thể chạy bất cứ lúc nào mà không làm ảnh hưởng đến cấu trúc chính của trang.
Thuộc tính defer của thẻ <script>: tải trì hoãn là gì?
Thuộc tính defer cũng là một thuộc tính boolean, nhưng nó cung cấp một cơ chế tải script có trật tự và ít gây gián đoạn hơn so với async.

Định nghĩa và nguyên lý hoạt động của defer
Khi trình duyệt gặp <script defer src="…">, nó cũng sẽ tải script về song song với việc phân tích HTML, tương tự async. Điểm khác biệt cốt lõi là script sẽ không được thực thi ngay khi tải xong. Thay vào đó, nó sẽ chờ cho đến khi toàn bộ tài liệu HTML được phân tích xong, ngay trước khi sự kiện DOMContentLoaded được kích hoạt. Các script có thuộc tính defer sẽ luôn được thực thi theo đúng thứ tự chúng xuất hiện trong HTML. Để hiểu sâu hơn, bạn có thể tham khảo bài viết về defer script để có cái nhìn toàn diện.
Ví dụ mã nguồn chi tiết và kết quả mong đợi
Với đoạn mã này, script1.js và script2.js được tải song song, nhưng script1.js luôn được đảm bảo thực thi trước script2.js, và cả hai chỉ chạy sau khi toàn bộ HTML đã được phân tích.
<script defer src="script1.js"></script>
<script defer src="script2.js"></script>
<p>Nội dung trang web…</p>
Kết quả là trang hiển thị nhanh chóng, và các script được thực thi một cách có trật tự, an toàn để tương tác với DOM.
Ưu điểm và nhược điểm của defer
Ưu điểm: Không chặn việc phân tích HTML. Đảm bảo thứ tự thực thi. An toàn cho các script cần thao tác với toàn bộ DOM.
Nhược điểm: Việc thực thi script bị trì hoãn cho đến khi toàn bộ trang được phân tích, có thể không phù hợp cho các script cần chạy sớm nhất có thể.
Khi nào nên sử dụng defer? (với các script phụ thuộc DOM, cần thứ tự)
Sử dụng defer là lựa chọn tốt nhất cho các script tương tác với DOM, chẳng hạn như các thư viện JavaScript (jQuery, React), các script xử lý giao diện người dùng, hoặc bất kỳ script nào phụ thuộc vào sự tồn tại của các script khác.
So sánh chuyên sâu: async vs defer vs không thuộc tính
Để lựa chọn đúng thuộc tính cho từng trường hợp, việc so sánh trực tiếp các đặc điểm là rất quan trọng.
Bảng so sánh đa chiều (tải, phân tích DOM, thực thi, thứ tự, tương thích)
|
Tiêu chí |
Script thường (Không thuộc tính) |
async |
defer |
Gợi ý chọn |
|
Chặn phân tích HTML |
Có, trong cả quá trình tải và thực thi |
Chỉ chặn lúc thực thi |
Không |
defer là tốt nhất để tránh chặn hiển thị |
|
Tải song song |
Không |
Có |
Có |
Cả async và defer đều cải thiện hiệu suất tải |
|
Thời điểm thực thi |
Ngay sau khi tải xong |
Ngay sau khi tải xong |
Sau khi phân tích xong HTML |
defer an toàn hơn cho các script thao tác DOM |
|
Đảm bảo thứ tự |
Có, theo thứ tự xuất hiện |
Không |
Có, theo thứ tự xuất hiện |
Dùng defer khi thứ tự là quan trọng |
|
Tương thích trình duyệt |
Tất cả |
Tất cả trình duyệt hiện đại |
Tất cả trình duyệt hiện đại |
An toàn để sử dụng rộng rãi |
Sơ đồ luồng hoạt động của trình duyệt cho từng trường hợp
Một sơ đồ trực quan sẽ giúp làm rõ khái niệm về luồng xử lý của trình duyệt:
Script thường: HTML Parsing -> Gặp Script -> Dừng Parsing -> Tải Script -> Thực thi Script -> Tiếp tục Parsing HTML.
Async Script: HTML Parsing (song song) Tải Script -> Tải xong -> Dừng Parsing -> Thực thi Script -> Tiếp tục Parsing HTML.
Defer Script: HTML Parsing (song song) Tải Script -> Parsing HTML xong -> Thực thi Script.
Tương tác với type='module' (hành vi defer mặc định)
Một điểm quan trọng trong JavaScript hiện đại là các script được khai báo với type="module" sẽ có hành vi mặc định giống như defer. Điều này có nghĩa là chúng được tải song song và chỉ thực thi sau khi tài liệu được phân tích xong, đồng thời vẫn giữ nguyên thứ tự. Đây là một cơ chế an toàn và hiệu quả cho các ứng dụng web module hóa.
Tác động của async và defer đến hiệu suất website và core web vitals
Việc tối ưu tải script không chỉ là một kỹ thuật lập trình mà còn là một yếu tố SEO kỹ thuật quan trọng, ảnh hưởng trực tiếp đến các chỉ số Core Web Vitals của Google.
Cải thiện largest contentful paint (LCP) và first input delay (FID)
Script chặn hiển thị là kẻ thù số một của LCP. Khi trình duyệt bị chặn, nó không thể hiển thị phần tử nội dung lớn nhất (thường là hình ảnh hoặc khối văn bản). Bằng cách sử dụng async hoặc defer, bạn cho phép trình duyệt tiếp tục phân tích và hiển thị nội dung, giúp cải thiện đáng kể điểm LCP. Tương tự, việc giải phóng luồng chính (main thread) khỏi việc thực thi JavaScript nặng nề cũng giúp trình duyệt phản hồi nhanh hơn với tương tác của người dùng, qua đó cải thiện chỉ số FID (hoặc Interaction to Next Paint – INP trong tương lai).
Phân tích các chỉ số hiệu suất với ví dụ minh họa (lighthouse scores)
Chạy một bài kiểm tra Lighthouse trước và sau khi áp dụng async/defer cho các script không quan trọng sẽ cho thấy sự khác biệt rõ rệt. Điểm Performance có thể tăng đáng kể, và các cảnh báo về "Eliminate render-blocking resources" sẽ biến mất. Ví dụ, một trang có điểm Performance là 60 có thể dễ dàng tăng lên 80-90 chỉ bằng cách thêm thuộc tính defer vào các file JavaScript lớn.
Tối ưu hóa các script bên thứ ba (quảng cáo, chatbot, phân tích)
Các script từ bên thứ ba thường là nguyên nhân chính gây chậm trang. Bạn không thể kiểm soát nội dung của chúng, nhưng bạn có thể kiểm soát cách chúng được tải. Luôn sử dụng async cho các script này (như script quảng cáo, chatbot, pixel theo dõi) để đảm bảo chúng không ảnh hưởng đến trải nghiệm tải trang cốt lõi. Hiểu rõ những điểm cần biết về script bên thứ ba là bước đầu tiên để kiểm soát tác động của chúng.
Hướng dẫn thực tế: áp dụng async và defer với các công cụ phổ biến
Lý thuyết cần đi đôi với thực hành. Dưới đây là cách áp dụng async và defer cho các công cụ phổ biến nhất.
Sử dụng async với google analytics (GA4) và google tag manager (GTM)
Đoạn mã cài đặt mặc định của Google Analytics 4 (gtag.js) và Google Tag Manager đã được tối ưu sẵn với thuộc tính async. Điều này đảm bảo việc thu thập dữ liệu không ảnh hưởng đến tốc độ tải trang của bạn.
Ví dụ mã cài đặt GA4:
<!– Google tag (gtag.js) –>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
</script>
Bạn chỉ cần đảm bảo giữ nguyên thuộc tính async trong đoạn mã này.
Tối ưu hóa thư viện javascript (jquery, react, vue) với defer
Khi sử dụng các thư viện như jQuery hoặc các framework như React/Vue mà script của bạn cần tương tác với DOM, defer là lựa chọn tối ưu. Đặt các script này ở cuối thẻ <body> cùng với thuộc tính defer để đảm bảo chúng không chặn hiển thị và chỉ chạy khi DOM đã sẵn sàng.
Ví dụ:
<script src="https://code.jquery.com/jquery-3.6.0.min.js" defer></script>
<script src="app.js" defer></script>
Checklist: chọn async hay defer trong từng tình huống
Sử dụng bảng dưới đây như một checklist nhanh để đưa ra quyết định chính xác.
|
Hạng mục |
Chi tiết thực hiện |
Mức độ ưu tiên |
|
Kiểm tra sự phụ thuộc |
Script có cần chạy theo một thứ tự cụ thể hoặc phụ thuộc vào script khác không? Nếu có, hãy dùng defer. |
Cao |
|
Tương tác với DOM |
Script có cần truy cập hoặc sửa đổi các phần tử HTML không? Nếu có, defer là lựa chọn an toàn nhất. |
Cao |
|
Mức độ quan trọng |
Script có cần thiết cho việc hiển thị nội dung đầu tiên không? Nếu không, dùng async (ví dụ: analytics, ads). |
Trung bình |
|
Script độc lập |
Script có hoạt động hoàn toàn độc lập không? Nếu có, async là lựa chọn hoàn hảo. |
Trung bình |
|
Vị trí script |
Nếu bắt buộc phải đặt script trong thẻ <head>, async hoặc defer là bắt buộc để tránh chặn hiển thị. |
Cao |
Khắc phục sự cố thường gặp (troubleshooting) khi sử dụng async và defer
Việc áp dụng async và defer đôi khi có thể gây ra lỗi không mong muốn. Dưới đây là cách chẩn đoán và khắc phục các vấn đề phổ biến.
|
Lỗi |
Dấu hiệu |
Nguyên nhân |
Cách khắc phục |
Mức độ ưu tiên |
|
Lỗi … is not defined |
Console báo lỗi biến hoặc hàm không được định nghĩa. |
Script phụ thuộc (ví dụ: app.js dùng jQuery) thực thi trước thư viện của nó (jquery.js) do dùng async. |
Chuyển tất cả các script phụ thuộc sang defer. defer đảm bảo thứ tự thực thi. |
Cao |
|
Script không tương tác được với DOM |
Script chạy nhưng không tìm thấy phần tử HTML nó cần (getElementById trả về null). |
Script dùng async được thực thi trước khi phần tử DOM tương ứng được trình duyệt phân tích. |
Sử dụng defer để đảm bảo script chỉ chạy sau khi toàn bộ HTML đã được phân tích. |
Cao |
|
Thứ tự logic bị sai |
Các chức năng của trang web hoạt động không đúng thứ tự mong đợi. |
Sử dụng async cho một chuỗi các script cần thực thi tuần tự. async không đảm bảo thứ tự. |
Nhóm các script này lại và sử dụng defer cho tất cả chúng theo đúng thứ tự. |
Trung bình |
|
Xung đột với script inline |
Script inline cố gắng gọi một hàm từ file async/defer nhưng file đó chưa được thực thi. |
Script inline thực thi ngay lập tức, trong khi script async/defer thì không. |
Bọc mã trong script inline vào một hàm lắng nghe sự kiện DOMContentLoaded hoặc load. |
Trung bình |
Kết luận: tối ưu tải script để có trải nghiệm người dùng vượt trội
Việc hiểu và sử dụng chính xác async và defer không còn là một lựa chọn mà đã trở thành yêu cầu bắt buộc trong phát triển web hiện đại và SEO kỹ thuật. Bằng cách loại bỏ các tài nguyên chặn hiển thị, bạn không chỉ cải thiện các chỉ số Core Web Vitals quan trọng mà còn mang lại trải nghiệm nhanh hơn, mượt mà hơn cho người dùng. Hãy bắt đầu kiểm tra website của bạn ngay hôm nay, xác định các script có thể tối ưu và áp dụng async cho các script độc lập, defer cho các script phụ thuộc để mở khóa toàn bộ tiềm năng về hiệu suất.
Bài viết liên quan
https://v4seowebsite.vn/prerendering-la-gi/