Tải JavaScript không đồng bộ - tăng tốc độ tải trang. JavaScript không đồng bộ và lười biếng

Chào hỏi những người bạn! Bạn có biết rằng tải JavaScript là một trong những điểm nghẽn lớn nhất trong hiệu suất trang web? Hôm nay nhiệm vụ chính của tôi là giải thích script là gì và nó ảnh hưởng như thế nào đến tốc độ cũng như hiệu suất của trang web.

Trình duyệt tải thẻ tập lệnh sẽ dừng hiển thị trang cho đến khi tập lệnh được tải và thực thi. Trang bị chặn và trình duyệt không phản hồi hành động của người dùng trong vài giây. Thời gian trễ phụ thuộc vào nhiều yếu tố:

  • cấu hình,
  • Tốc độ kết nối Internet,
  • kích thước tập tin và những thứ khác...

Vì lý do này, công cụ phân tích tốc độ trang web của Google PageSpeed ​​​​Insights khuyên bạn nên xóa mã JavaScript chặn hiển thị ở đầu trang. Một cách tốt là đặt các tập lệnh ở cuối trang web, chẳng hạn như trước thẻ đóng hoặc thiết lập tải không đồng bộ.

Nếu mã tập lệnh ảnh hưởng đến việc hiển thị phần trên cùng của trang web, đừng đặt nó vào một tệp riêng mà hãy nhúng trực tiếp vào HTML.

JS có thể thay đổi nội dung của trang web và thậm chí chuyển hướng đến một URL khác. Trong trường hợp này, việc nối script ở cuối tài liệu sẽ dẫn đến hiệu ứng “co giật” trang, tải mới hoặc thay đổi các thành phần hiện có ở trên cùng.

Áp dụng thuộc tính async và defer cho thẻ script

Hãy cùng tìm hiểu công việc không đồng bộ và trì hoãn trong JavaScript là gì cũng như sự khác biệt cơ bản giữa thuộc tính async và defer. Nhưng trước tiên, hãy xem xét trình tự xử lý tài liệu với việc bao gồm thẻ tập lệnh thông thường.

1 < src = "example.js" >

Đối với ví dụ minh họa này, tôi sẽ sử dụng các quy ước sau:

- xử lý trang
- tải tập lệnh
- thực thi tập lệnh

Do đó, trình tự xử lý xảy ra theo sơ đồ sau:

Quá trình phân tích mã HTML bị gián đoạn trong khi tập lệnh đang tải và thực thi, sau đó nó vẫn tiếp tục. Có sự chậm trễ trong việc hiển thị trang web.

thuộc tính trì hoãn

Thuộc tính defer cho phép trình duyệt bắt đầu tải xuống các tệp js song song mà không dừng quá trình xử lý trang. Việc thực thi chúng xảy ra sau khi phân tích cú pháp hoàn chỉnh mô hình đối tượng tài liệu (từ Mô hình đối tượng tài liệu tiếng Anh, viết tắt DOM), trong khi trình duyệt đảm bảo tính nhất quán dựa trên thứ tự các tệp được kết nối.

1 < defer src = "example.js" >

thuộc tính không đồng bộ

Hỗ trợ thuộc tính async đã xuất hiện trong HTML5, nó cho phép trình duyệt tải xuống các tệp js song song và thực thi chúng ngay sau khi tải xuống mà không cần đợi phần còn lại của trang được xử lý.

1 < async src = "example.js" >

Sơ đồ trình tự xử lý:

Đây là bản tải xuống không đồng bộ. Thuộc tính này được khuyến nghị sử dụng trong các tập lệnh không có tác động đáng kể đến việc hiển thị tài liệu. Chúng bao gồm các bộ đếm thu thập số liệu thống kê (Google Analytics, Yandex Metrica), mã mạng quảng cáo (Mạng quảng cáo Yandex, Google AdSense), các nút mạng xã hội, v.v.

Tốc độ tải trang web là một trong những yếu tố xếp hạng trên Google.

Kết nối JavaScript không đồng bộ giúp giảm thời gian tải trang bằng cách loại bỏ độ trễ. Ngoài ra, tôi khuyên bạn nên nén và hợp nhất các tệp js thành một, chẳng hạn như sử dụng phần mở rộng . Người dùng thích các trang web nhanh 😎

Các trang web hiện đại được tải rất nhiều tệp javascript. Điều này dẫn đến việc tải trang và hiển thị trang sau đó chậm hơn. Trong điều kiện tồi tệ nhất, người truy cập trang web phải đợi tới 30 giây.

Tăng tốc độ tải trang html

Sử dụng JavaScript hiện đại

Các trang web hiện đại được tải rất nhiều tệp javascript. Điều này dẫn đến việc tải trang và hiển thị trang sau đó chậm hơn. Trong điều kiện tồi tệ nhất (kết nối Internet chậm, nhiều tệp javascript), người truy cập trang web phải chờ tới 30 giây.

HTML được thiết kế theo cách một trang web tải bằng cách tải đồng bộ (từng dòng một) lần lượt tất cả các phần tử có trong mã HTML.

Có một giải pháp: đặt các dòng Javascript ở cuối tài liệu html (do đó, chúng sẽ được tải sau khi toàn bộ trang được vẽ) và chỉ sau đó nội dung của các khối mới được hiển thị ở đúng vị trí. Nó được gọi là .

Tất cả các dự án nghiêm túc hiện nay đều cố gắng chuyển sang công nghệ tải mới càng nhanh càng tốt. Hơn nữa, nó hoàn toàn dễ dàng.

Có một số cách tiếp cận. Tôi sẽ bắt đầu theo thứ tự.

< script src= "//www.site.ru/script.js" type= "text/javascript" >

Chuẩn HTML5 hỗ trợ khả năng tải tập lệnh không đồng bộ, điều này có thể tăng tốc đáng kể thời gian truy xuất trang tổng thể. Chỉ cần thêm async hoặc defer .

< script async src= "//www.site.ru/script.js" type= "text/javascript" >

< script defer src= "//www.site.ru/script.js" type= "text/javascript" >

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

Trong cả hai trường hợp, chúng tôi nhận được tải tập lệnh không đồng bộ. Sự khác biệt duy nhất là thời điểm tập lệnh bắt đầu thực thi. Tập lệnh có thuộc tính async sẽ được thực thi càng sớm càng tốt sau khi được tải đầy đủ, nhưng trước khi đối tượng cửa sổ được tải. Nếu thuộc tính defer được sử dụng, tập lệnh sẽ không vi phạm thứ tự thực thi của nó so với các tập lệnh khác và việc thực thi nó sẽ xảy ra sau khi trang được tải và phân tích cú pháp đầy đủ, nhưng trước sự kiện DOMContentLoaded của đối tượng tài liệu.

Thật không may, cơ chế này hiện không hoạt động trên tất cả các trình duyệt (đặc biệt là IE). Cũng sẽ không hoạt động nếu có dòng document.write trong tệp script.js.

Như tất cả các chuyên gia đều biết, Google đặc biệt chú ý đến tốc độ tải trang web và giảm tốc độ tải trang chậm trong kết quả tìm kiếm. Để trợ giúp, Google đã phát triển một tập lệnh đặc biệt mà bạn có thể sử dụng để tải javascript không đồng bộ.

Để sử dụng, chỉ cần thay thế

TRÊN

Và kết nối tập lệnh extsrc.js

Nó sẽ diễn ra như thế này:

< script src= "//extsrcjs.googlecode.com/svn/trunk/extsrc.js" > < script extsrc= "...." >

Thật không may, phương pháp này cũng không hoạt động đối với các tệp có document.write

Một phương pháp phổ quát cho tất cả các trình duyệt. Thậm chí còn hoạt động với document.write

Ở vị trí trên trang mà chúng ta cần hiển thị phần tử của mình, hãy tạo một khối div trống:

< div id= "script_block" class = "script_block" >

Ở cuối trang, trước khi chúng tôi chèn tập lệnh để tải tệp không đồng bộ:

< div id= "script_ad" class = "script_ad" style= "display:none;" >Đây là bất kỳ tập tin hoặc tập lệnh nào cần được tải.< script type= "text/javascript" >// di chuyển nó đến tài liệu vị trí hiển thị thực tế. getElementById("script_block" ). appendChild(document. getElementById("script_ad" ) ); // hiển thị tài liệu. getElementById("script_ad" ). phong cách. hiển thị = "chặn";

Rất tiếc, trong các phiên bản IE cũ nhất (6 trở xuống), tải không đồng bộ không hoạt động, nhưng thực tế không còn những người dùng như vậy nữa. Tất cả các trình duyệt và dịch vụ khác đều sử dụng thành công khả năng tải trang web tăng tốc hiện đại.

Có một giải pháp: đặt các dòng Javascript ở cuối tài liệu html (do đó, chúng sẽ được tải sau khi toàn bộ trang được vẽ) và chỉ sau đó nội dung của các khối mới được hiển thị ở đúng vị trí. Nó được gọi là . Tất cả các dự án nghiêm túc hiện nay đều cố gắng chuyển sang công nghệ tải mới càng nhanh càng tốt. Hơn nữa, nó hoàn toàn dễ dàng.

Có một số cách tiếp cận. Tôi sẽ bắt đầu theo thứ tự.

tập lệnh src= type= "văn bản/javascript" >

Tải tập lệnh HTML5 không đồng bộ

Chuẩn HTML5 hỗ trợ khả năng tải tập lệnh không đồng bộ, điều này có thể tăng tốc đáng kể thời gian truy xuất trang tổng thể. Chỉ cần thêm async hoặc defer .

< script async src= "http://www.site.ru/script.js" type= "text/javascript" >

< script defer src= "http://www.site.ru/script.js" type= "text/javascript" >

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

Trong cả hai trường hợp, chúng tôi nhận được tải tập lệnh không đồng bộ. Sự khác biệt duy nhất là thời điểm tập lệnh bắt đầu thực thi. Tập lệnh có thuộc tính async sẽ được thực thi càng sớm càng tốt sau khi được tải đầy đủ, nhưng trước khi đối tượng cửa sổ được tải. Nếu thuộc tính defer được sử dụng, tập lệnh sẽ không vi phạm thứ tự thực thi của nó so với các tập lệnh khác và việc thực thi nó sẽ xảy ra sau khi trang được tải và phân tích cú pháp đầy đủ, nhưng trước sự kiện DOMContentLoaded của đối tượng tài liệu.

Thật không may, cơ chế này hiện không hoạt động trên tất cả các trình duyệt (đặc biệt là IE). Cũng sẽ không hoạt động nếu có dòng document.write trong tệp script.js.

Tải javascript không đồng bộ bằng tập lệnh Google

Như tất cả các chuyên gia đều biết, Google đặc biệt chú ý đến tốc độ tải trang web và giảm tốc độ tải trang chậm trong kết quả tìm kiếm. Để trợ giúp, Google đã phát triển một tập lệnh đặc biệt mà bạn có thể sử dụng để tải javascript không đồng bộ.

Để sử dụng, chỉ cần thay thế

TRÊN

Và kết nối tập lệnh extsrc.js

Nó sẽ diễn ra như thế này:

< script src= "http://extsrcjs.googlecode.com/svn/trunk/extsrc.js" > < script extsrc= "...." >

Thật không may, phương pháp này cũng không hoạt động đối với các tệp có document.write

Tải javascript không đồng bộ hoạt động tốt nhất

Một phương pháp phổ quát cho tất cả các trình duyệt. Thậm chí còn hoạt động với document.write

Ở vị trí trên trang mà chúng ta cần hiển thị phần tử của mình, hãy tạo một khối div trống:

< div id= "script_block" class = "script_block" >

Ở cuối trang, trước khi chúng tôi chèn tập lệnh để tải tệp không đồng bộ:

< div id= "script_ad" class = "script_ad" style= "display:none;" >Đây là bất kỳ tập tin hoặc tập lệnh nào cần được tải.< script type= "text/javascript" >// di chuyển nó đến tài liệu vị trí hiển thị thực tế. getElementById("script_block" ). appendChild(document. getElementById("script_ad" ) ); // hiển thị tài liệu. getElementById("script_ad" ). phong cách. hiển thị = "chặn";

Rất tiếc, trong các phiên bản IE cũ nhất (6 trở xuống), tải không đồng bộ không hoạt động, nhưng thực tế không còn những người dùng như vậy nữa. Tất cả các trình duyệt và dịch vụ khác đều sử dụng thành công khả năng tải trang web tăng tốc hiện đại.

HTML được thiết kế theo cách trang web được tải tuần tự từng dòng, tải lần lượt tất cả các phần tử có trong mã html. Và nếu một trong số chúng không có sẵn (ví dụ: javaScript từ một trang bên ngoài không được đọc), thì việc tải trang tiếp theo sẽ dừng lại.

Khi JS không thể đọc được ở đầu trang, khách truy cập có thể không nhìn thấy gì cả.

Do đó, khi bạn sử dụng JavaScript từ các trang web của bên thứ ba trên trang web của mình, chẳng hạn như để hiển thị quảng cáo, bạn nên tải chúng không đồng bộ. Trong trường hợp này, JS của bên thứ ba sẽ không trì hoãn việc tải và hiển thị trang web của bạn.

Thật không may, không phải tất cả các mạng quảng cáo đều cung cấp khả năng tải xuống tập lệnh không đồng bộ. Vì vậy, trong bài viết này tôi sẽ hướng dẫn bạn cách thay đổi mã tải đồng bộ thành không đồng bộ. Nếu chủ sở hữu tập lệnh này không cung cấp tùy chọn này.

Tải JS đồng bộ tiêu chuẩn

Thông thường, việc gọi một tập lệnh từ máy chủ bên ngoài trông như thế này:

Tải tập lệnh không đồng bộ giống như Google/Adsense

Tôi lấy ý tưởng từ Google/Adsense. Để tập lệnh tải không đồng bộ từ phần còn lại của mã HTML, bạn cần thêm async vào mã cuộc gọi.

Và bây giờ để mã tải không đồng bộ, lệnh gọi tập lệnh của chúng ta từ máy chủ bên ngoài sẽ trông như thế này:

Như bạn có thể thấy, mọi thứ đều đơn giản. Đúng, điều này sẽ chỉ hoạt động trong các trình duyệt hỗ trợ chuẩn HTML5. Tại thời điểm viết bài này, có phần lớn các trình duyệt như vậy.

Tùy chọn được đề xuất không phổ biến 100%. Nhiều tập lệnh ngừng hoạt động sau khi thực hiện những thay đổi này. Theo đánh giá trên Internet, phương pháp này không hoạt động nếu phần tử được sử dụng trong tập lệnh tài liệu.write.

Tùy chọn tải không đồng bộ đáng tin cậy

Nếu tùy chọn được đề xuất đầu tiên không phù hợp với bạn. Sau đó sử dụng các khuyến nghị sau đây. Đây thực chất là lười tải. Vì lệnh gọi thực tế tới tập lệnh xảy ra ở cuối trang HTML, nghĩa là khi tất cả nội dung cần thiết của trang đã có trên màn hình.

Ở vị trí trên trang mà bạn muốn hiển thị kết quả của JavaScript, bạn cần tạo một khối div trống:

Sau đó, ở cuối trang trước thẻ BODY đóng, chúng tôi chèn một tập lệnh để tải không đồng bộ:

// JavaScript cần được tải không đồng bộ // di chuyển nó đến vị trí hiển thị thực tế document.getElementById("script_block_0").appendChild(document.getElementById("script_ad_0")); // hiển thị document.getElementById("script_ad_0").style.display = "block";

Nếu có một số khối quảng cáo, thì đối với mỗi khối đó, bạn cần lặp lại mọi thứ, tạo các khối DIV riêng lẻ duy nhất. Đừng quên thay đổi tên lớp và ID DIV. Trong ví dụ của tôi, chỉ cần thay đổi số 0 là đủ, trong khối mới, nó cần được thay thế bằng 1, v.v.

Tùy chọn này phức tạp hơn, nhưng nó hoạt động ở mọi nơi ngoại trừ các trình duyệt rất cổ xưa như Internet Explorer 6. May mắn thay, thực tế không còn tìm thấy trên máy tính người dùng.

) Tôi đã viết về tác động của các tệp JavaScript đối với Đường dẫn hiển thị quan trọng (CRP).


JavaScript là tài nguyên chặn cho trình phân tích cú pháp. Điều này có nghĩa là JavaScript chặn việc phân tích cú pháp tài liệu HTML. Khi trình phân tích cú pháp chạm đến thẻ ‹script> (không quan trọng là bên trong hay bên ngoài), nó sẽ dừng lại, chọn tệp (nếu là bên ngoài) và chạy nó.

Hành vi này có thể có vấn đề nếu chúng tôi tải nhiều tệp JavaScript trên một trang vì nó làm tăng thời gian hiển thị lần đầu ngay cả khi tài liệu không thực sự phụ thuộc vào các tệp đó.


May mắn thay, phần tử này có hai thuộc tính, async và defer, cho phép chúng ta kiểm soát cách tải và thực thi các tệp bên ngoài.

Thực hiện bình thường

Trước khi hiểu sự khác biệt giữa hai thuộc tính này, chúng ta hãy xem điều gì sẽ xảy ra khi chúng vắng mặt. Như đã nêu trước đó, theo mặc định, các tệp JavaScript sẽ làm gián đoạn quá trình phân tích cú pháp tài liệu HTML cho đến khi chúng được nhận và thực thi.
Hãy lấy một ví dụ trong đó phần tử nằm ở đâu đó ở giữa trang:


... ... ....

Đây là điều sẽ xảy ra khi trình phân tích cú pháp xử lý tài liệu:

Quá trình phân tích cú pháp HTML bị tạm dừng cho đến khi tập lệnh được tải xuống và thực thi, do đó sẽ tăng lượng thời gian cho đến lần hiển thị đầu tiên.

thuộc tính không đồng bộ

Async được sử dụng để cho trình duyệt biết rằng tập lệnh Có lẽđược thực hiện không đồng bộ.
Trình phân tích cú pháp HTML không cần dừng lại khi đến thẻ để tải và thực thi. Việc thực thi có thể xảy ra sau khi tập lệnh được nhận song song với việc phân tích cú pháp tài liệu.



Thuộc tính chỉ khả dụng cho các tệp được kết nối bên ngoài. Nếu một tệp bên ngoài có thuộc tính này thì nó có thể được tải trong khi tài liệu HTML vẫn đang được phân tích cú pháp. Trình phân tích cú pháp sẽ tạm dừng để thực thi tập lệnh ngay khi tệp tập lệnh được tải.



thuộc tính trì hoãn

Thuộc tính defer cho trình duyệt biết rằng tập lệnh sẽ được thực thi sau khi tài liệu HTML được phân tích cú pháp hoàn toàn.



Giống như việc tải tập lệnh không đồng bộ, tệp có thể được tải trong khi tài liệu HTML đang được phân tích cú pháp. Tuy nhiên, ngay cả khi tệp tập lệnh được tải đầy đủ trước khi trình phân tích cú pháp kết thúc, nó sẽ không được thực thi cho đến khi trình phân tích cú pháp chạy xong.



Thực thi không đồng bộ, bị trì hoãn hoặc bình thường?

Vì vậy, khi nào bạn nên sử dụng thực thi JavaScript không đồng bộ, lười biếng hoặc bình thường? Như thường lệ, điều này tùy thuộc vào tình huống và có một số câu hỏi có thể giúp bạn đưa ra quyết định đúng đắn.

Phần tử nằm ở đâu?

Việc thực thi không đồng bộ và lười biếng là quan trọng nhất khi phần tử không nằm ở cuối tài liệu. Các tài liệu HTML được phân tích theo thứ tự từ mở đến đóng. Nếu tệp JavaScript bên ngoài được đặt ngay trước thẻ đóng thì việc sử dụng async và defer sẽ ít thích hợp hơn vì lúc đó trình phân tích cú pháp sẽ phân tích hầu hết tài liệu và các tệp JavaScript sẽ không còn ảnh hưởng đến nó nữa.

Kịch bản có tự cung cấp được không?

Đối với các tệp không phụ thuộc vào các tệp khác và/hoặc không có bất kỳ phần phụ thuộc nào, thuộc tính async sẽ hữu ích nhất. Vì chúng ta không quan tâm đến thời điểm tệp được thực thi nên tải không đồng bộ là tùy chọn phù hợp nhất.

Tập lệnh có dựa trên DOM được phân tích cú pháp đầy đủ không?

Trong nhiều trường hợp, tệp tập lệnh chứa các hàm tương tác với DOM. Hoặc có lẽ có sự phụ thuộc vào một tệp khác trên trang. Trong những trường hợp như vậy, DOM phải được phân tích cú pháp hoàn toàn trước khi tập lệnh được thực thi. Thông thường, một tệp như vậy được đặt ở cuối trang để đảm bảo rằng mọi thứ đã được phân tích cú pháp để nó hoạt động. Tuy nhiên, trong trường hợp vì lý do nào đó mà tệp phải được đặt ở một vị trí khác, thuộc tính defer có thể hữu ích.

Kịch bản nhỏ và phụ thuộc?

Cuối cùng, nếu tập lệnh tương đối nhỏ và/hoặc phụ thuộc vào các tệp khác thì có thể cần xác định nội tuyến. Mặc dù mã nội tuyến chặn việc phân tích cú pháp tài liệu HTML nhưng sẽ không có vấn đề gì lớn nếu tài liệu có kích thước nhỏ. Ngoài ra, nếu nó phụ thuộc vào các tệp khác, có thể cần một số khóa nhỏ.

Hỗ trợ và công cụ trình duyệt hiện đại

Hỗ trợ cho các thuộc tính async và defer rất phổ biến:




Cần lưu ý rằng hoạt động của các thuộc tính này có thể hơi khác nhau giữa các công cụ JavaScript. Ví dụ: trong V8 (được sử dụng trong Chrome), một nỗ lực được thực hiện để phân tích tất cả các tập lệnh, bất kể thuộc tính của chúng, thành một luồng chuyên dụng riêng biệt để thực thi tập lệnh. Do đó, tính chất "chặn trình phân tích cú pháp" của tệp JavaScript phải được giảm thiểu theo mặc định.