Bài này mình xin giới thiệu sơ qua về cách trình duyệt tải nội dung HTML và CSS như thế nào.

1. Thứ tự thực hiện khi trình duyệt tải nội dung HTML và JS.

  1. Lấy nội dung trang HTML (ví dụ index.html)
  2. Bắt đầu dịch (parse) trang HTML cho trình duyệt.
  3. Nếu bộ dịch của trình duyệt gặp phải thẻ <script> mà tham chiếu tới file script ngoài.
  4. Trình duyệt sẽ gửi request để lấy nội dung file script đó, trong quá trình gửi request này, trình duyệt sẽ tạm ngừng quá trình dịch phần HTML còn lại.
  5. Sau khi file script đã được download thành công thì trình duyệt sẽ thực thi file script này.
  6. Sau khi thực thi file script xong thì trình duyệt mới quay trở lại dịch tiếp phần HTML còn lại.

 

2. Lỗi khi file script thực thi trước khi DOM được load xong.

Trong nhiều trường hợp, nếu các bạn đặt thẻ <script> trong thẻ <head> thì những phần thực thi đối với DOM chưa được load xong sẽ không chạy.

<!-- index.html -->
<html>
    <head>
        <title>My Page</title>
        <script type="text/javascript" src="my-script.js"></script>
    </head>
    <body>
        <div id="user-greeting">Welcome back, user</div>
    </body>
</html>

 

 

// my-script.js
document.addEventListener("DOMContentLoaded", function() { 
    // this function runs when the DOM is ready, i.e. when the document has been parsed
    document.getElementById("user-greeting").textContent = "Welcome back, Bart";
});

 

 

Đoạn code trên sẽ không thay thế "Welcome back, user" thành "Welcome back, Bart" vì khi load file my-script.js thì phần HTML phía dưới chưa được load nên đoạn code trong script sẽ không hiểu.

3. Lời khuyên truyền thống.

Để phòng tránh lỗi trên thì có một cách làm truyền thống là đặt thẻ <script> ở sau cùng.

Nhưng nếu làm thế thì phải đợi HTML load xong rồi thì script mới tới lượt được load, dẫn tới hiệu năng sẽ giảm nếu page có nhiều file script. Khi bắt người dùng chờ trên 2s cho một page load xong thì họ có xu hướng đi ra trang khác.

4. Cách làm hiện đại

Các browser ngày nay hỗ trợ các thuộc tính asyncdefer trong thẻ script:

 

- assync cho phép các thẻ script download mà không làm ngừng bộ dịch HTML:

 

<script type="text/javascript" src="path/to/script1.js" async></script>
<script type="text/javascript" src="path/to/script2.js" async></script>

 

assync scripts được thực thi ngay sau khi nó được download xong, và script2 hoàn toàn có thể được thực thi xong trước script1.

- defer thực thi theo thứ tự script nhưng vẫn không làm ngừng bộ dịch HTML:

<script type="text/javascript" src="path/to/script1.js" defer></script>
<script type="text/javascript" src="path/to/script2.js" defer></script>

 

Không như async, defer script chỉ thực thi sau khi document đã được load xong.

 

5. Kết luận.

Bạn nên đặt thẻ <script> trong thẻ <head> và sử dụng các thuộc tính assync hoặc defer.

 

Tham khảo từ http://stackoverflow.com/questions/436411/where-is-the-best-place-to-put-script-tags-in-html-markup