Thuộc tính async và defer trong JavaScript

Cập nhật lần cuối vào

Bạn thường hay thấy mọi người nhắc đến nên load JavaScript ở phía trước kết thúc thẻ body. Bài viết này mình sẽ cùng các bạn thảo luận qua về thuộc tính async và defer trong JavaScript, liệu 2 thuộc tính này có liên quan gì đến câu nói của mọi người?

Thuộc tính async và defer trong JavaScript

Ngày nay, khi mà các trình duyệt đã phát triển vượt bậc, đại đa số các trình duyệt đều hỗ trợ HTML5 và CSS3, bạn cũng nên tìm hiểu chút ít về cách sử dụng async và defer trong khi tải JavaScript chạy trên website.

Đối với thuộc tính async thì phiên bản IE 10 trở về sau mới hiểu được, còn các phiên bản cũ thì chưa có hỗ trợ async. Nhưng không sao, bạn vẫn có thể sử dụng thuộc tính defer để thay thế cho async. Cú pháp sử dụng rất đơn giản, bạn chỉ cần thêm vào thuộc tính cần sử dụng trong thẻ script như bên dưới:

// async
<script src="scripts.js" async></script>

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

Khi sử dụng async và defer thì bạn sẽ giải quyết được lỗi chặn hiển thị trong nội dung trong màn hình đầu tiên khi kiểm tra tốc độ website trên Google PageSpeed Insights. Câu hỏi được đặt ra ở đây là khi nào nên sử dụng async và khi nào nên dùng defer?

Khi bạn tải JavaScript theo cách thông thường, trình duyệt sẽ đọc trang web của bạn theo thứ tự từ trên xuống dưới, nếu gặp phải các đoạn mã JavaScript thì trình duyệt sẽ ngừng load HTML và xử lý code bên trong cho đến khi kết thúc thì mới tiếp tục tải tiếp, đó là lý do vì sao khi bạn kiểm tra tốc độ website trên PageSpeed của Google thì phát hiện lỗi Loại bỏ JavaScript và CSS chặn hiển thị trong nội dung trong màn hình đầu tiên.

<html>
<head>
    <script type="text/javascript" src="script-cua-ban.js"></script>
</head>
<body>
<div>
    Hello, world!
</div>
</body>
</html>

Nếu bạn sử dụng thuộc tính async trong khi tải JavaScript, khi trình duyệt đụng phải đoạn code load JavaScript thì HTML bên dưới vẫn tiếp tục tải, đồng thời JavaScript vẫn được tải cùng lúc, cho đến khi nội dung của JavaScript được tải xong thì các lệnh bên trong sẽ được thực thi, không phụ thuộc vào vị trí thứ tự bạn tải JavaScript trong website của bạn. Trong quá trình các lệnh JavaScript được thực thi thì HTML sẽ tạm ngừng tải cho đến khi JavaScript chạy xong.

<html>
<head>
    <script type="text/javascript" src="script-cua-ban.js" async></script>
</head>
<body>
<div>
    Hello, world!
</div>
</body>
</html>

Nếu bạn sử dụng thuộc tính defer trong khi tải JavaScript, khi trình duyệt đụng phải đoạn code load JavaScript thì HTML bên dưới vẫn tiếp tục tải, đồng thời JavaScript vẫn được tải cùng lúc. Các lệnh bên trong tập tin JavaScript sẽ không được chạy cho đến khi HTML được tải xong.

Như vậy, cả 2 thuộc tính async và defer đều có cách thức tải giống nhau, đều tải đồng thời với các thẻ HTML khác. Chỉ khác là thời gian thực thi, async thì được thực thi ngay sau khi JavaScript được tải xong (cho dù HTML có được tải xong hết hay chưa, trong quá trình JavaScript được thực thi thì HTML bên dưới sẽ ngừng tải), trong khi defer thì các lệnh được chạy chỉ khi HTML đã được tải xong.

Khi nào nên dùng async và defer?

Qua nội dung giới thiệu bên trên, bạn có thể hiểu được cách thức hoạt động của async và defer rồi. Việc quan trọng của bạn là phải biết khi nào bạn nên dùng async, khi nào nên dùng defer.

  • Nếu script của bạn là một module nào đó, chạy độc lập và không phụ thuộc vào bất kỳ script nào khác thì dùng thuộc tính async.
  • Nếu script của bạn phụ thuộc vào một script khác hoặc được một script khác sử dụng lại (phụ thuộc vào) thì nên sử dụng thuộc tính defer.
  • Nếu script của bạn nhỏ chỉ có vài dòng code thì xuất ngay các đoạn code vào bên trong thẻ script luôn (inline script), đừng tạo file JavaScript độc lập và không dùng 2 thuộc tính kia.
  • Nếu script của bạn nhỏ như bên trên (ít code), và được một script khác sử dụng thuộc tính async phụ thuộc vào thì xuất script theo kiểu inline và đặt trước đoạn script async.

Để cho bạn dễ hình dung và có thể hiểu được cách thức hoạt động của async và defer, bạn có thể tham khảo như hình ảnh mình gửi bên dưới.

Cách tải và thực thi JavaScript

Đối với các trình duyệt cũ, bạn có thể sử dụng kết hợp cả async và defer trong khi load script để phòng ngừa trường hợp trình duyệt không hiểu thuộc tính async. Đó là đối với các thuộc tính bạn quyết định dùng async thì nên bỏ thêm defer vào, nhưng nếu bạn không quan trọng tới vấn đề lỗi hiển thị trên trình duyệt cũ thì bạn không cần quan tâm tới điều này.