Defer và async hiệu quả khi load javascript

Nội dung bài viết

Bạn học đọc gì thông qua bài viết này?

Mấy hôm trước chúng tôi có phân tích về cách khắc phục sự cố web chậm hơn rất nhiều sau khi tích hợp Google analytics thông qua bài viết Cách khắc phục Google analytics làm chậm hệ thống. Ở đó chúng tôi đã có cách của riêng mình giúp hệ thống tối ưu từ 80 lên 99 về hiệu suất load page. Trong bài viết này bạn sẽ tiếp cận thêm một cách mà HTML5 đã support thêm đó là asyncdefer. Bạn sẽ có nhiều kiến thức về performance hơn, giúp hệ thống tối ưu nhiều hơn sau khi tham khảo bài viết này.

Ngoài ra thêm một gợi ý cho bạn cách các pro load js: Load a javascript file dynamically

Sử dụng script tag thông thường

Trước tiên đi vào vấn đề chính trong bài viết này, chúng ta nên quay lại thời gian trước kia một chút, để xem cách hoạt động khi bạn add một file script vào và để xem chuyện gì đã xảy ra. Ai cũng đã từng làm như thế này

<script src="/path/to/script.js"></script>

Ok, tất nhiên là rất bình thường, nhưng bây giờ ngay tại thời điểm bây giờ thì nó có vấn đề.

--──────────────────────┬───────────────────────────────────────┬───────────────────┐
/ Parse the document    / Pause parsing                         / Resume parsing    /
└───────────────────────┼───────────────────┬───────────────────┴───────────────────┘
                        / Download script   /
                        └───────────────────┼───────────────────┐
                                            / Execute script    /
                                            └───────────────────┘

Tôi nghĩ khi bạn nhìn vào thì có lẽ cũng đã đủ hiểu sự hạn chế của cách cũ như thế nào, nhưng cứ để tôi trình bày lại:

  • Đầu tiên khi user load page thì Document được phân tích (DOM...)
  • Khi gặp câu lệnh khai báo như trên thì việc phân tích Document dừng lại, nhường cho việc tải tài nguyên script về. Sau đó, sẽ thực thi những function trong file js đó.
  • Sau khi execute script xong thì tiếp tục thực thi việc phân tích DOM.

Bạn thấy thế nào? Đương nhiên là khi execute js thì chúng ta không thể sử dụng hệ thống được mà phải chờ... Chính vì những nhược điểm như vậy mà chúng ta phải thay đổi, điều đó đồng nghĩa với việc vì sao lại ra đời hai thuộc tính asyncdefer trong HTML.

Async và Defer là gì?

Trường hợp trên này mang lại trải nghiệm người dùng không tốt vì người dùng không thể tương tác với trang khi tập lệnh đang được tải xuống. Họ phải đợi tất cả các tập lệnh được tải xuống và thực thi hoàn chỉnh trước khi thấy toàn bộ trang được phân tích cú pháp. Để khắc phục sự cố đó, HTML 5 cung cấp hai thuộc tính cho thẻ script. Họ là async và defer. Trước hết chúng ta đi tìm hiểu Async và Defer là gì? Và vì sao chúng ta phải hiểu về khái niệm này?

<script src="/path/to/script.js" async></script>
<script src="/path/to/script.js" defer></script>

Async và Defer hai thuộc tính cho trình duyệt biết rằng các tập lệnh có thể được tải xuống song song với quá trình phân tích cú pháp tài liệu. Điều đó giúp cho người dùng trải nghiệm tốt hơn, và tối ưu hiệu suất nhanh hơn. OK, nếu nói đến đây thì nó rất chung chung chính vì vậy chúng ta nên đi tìm hiểu kỹ hơn về hai thuộc tính này.

Async Defer và sự khác biệt

Có một số điểm khác biệt giữa hai thuộc tính này như sau:

Đầu tiên mặc dù là các tài nguyên được tải song song với việc phân tích Document nhưng việc thực thi thì tại thời điểm khác nhau.

Xem quá trình sử dụng async:

┌───────────────────────────────────────────┬───────────────────┬───────────────────┐
/ Parse the document                        / Pause parsing     / Resume parsing    /
└───────────────────────┬───────────────────┼───────────────────┴───────────────────┘
                        / Download script   /
                        └───────────────────┼───────────────────┐
                                            / Execute script    /
                                            └───────────────────┘

Khi sử dụng async thì quá trình Execute script thì việc phân tích document phải dừng lại, và sau khi thực thi mã js thành công thì trình duyệt tiếp tục công việc parse Document.

Xem quá trình sử dụng defer:

 ───────────────────────────────────────────────────────────┐
/ Parse the document                                        /
└───────────────────────┬─────────────────┬─────────────────┘
                        / Download script /
                        └─────────────────┘                 ┌───────────────────┐
                                                            / Execute script    /
                                                            └───────────────────┘

Mặt khác defer, tập lệnh sẽ chỉ được thực thi khi trình phân tích cú pháp đã hoàn thành công việc của nó. NOTES: Khi sử dụng async thì được thực thi ngay sau khi nó được tải xuống hoàn toàn, do đó, chúng có thể không được thực thi theo cùng một thứ tự khi chúng xuất hiện trên trang. Mặt khác, các tập lệnh được sử dụng defer đảm bảo thứ tự thực hiện.

Vị trí đặt thẻ Async và Defer

Như vậy thì một tập lệnh thống kê (ví dụ: tập lệnh Google Analytic) sẽ phù hợp trong trường hợp sử dụng này. Chắc chắn sẽ có những câu hỏi như, vậy nên đặt ở đâu, trong tag header hay trên tab </body>. Theo cá nhân tôi, thì tốt nhất hãy đặt script ngay trước đó </body>.

 <body>
    ...
    <script src="..."></script>
    <script src="..."></script>
    <script src="..."></script>
</body>

So sánh hiệu suất Async and Defer

a. Không async và defer, đặt trong

b. Không async và defer, đặt trong

c. Dùng async, đặt trong

d. Dùng defer, đặt trong

Thông qua các hình ảnh các bạn cũng đã thấy cách nào là tối ưu rồi chứ?

Kết luận.

Đã quá rõ ràng, nếu bạn dùng async thì bạn không cần quan tâm những tập lệnh khác. Còn tập lệnh này liên quan đến file kìa thì nên sử dụng defer. Trừ khi bạn đã ổn định với tốc độ load trang của bạn, còn không hãy thay đổi và sử dụng theo cách này.

Bài viết sử dụng hình ảnh của: flaviocopes.com

Có thể bạn đã bị missing