Tải tập lệnh không đồng bộ. Chúng tôi đang tạo một dự án thử nghiệm. Hỗ trợ và công cụ trình duyệt hiện đại

Đôi khi cần phải tải dữ liệu không đồng bộ từng bước. Và nó có thể là bất cứ điều gì. Bắt đầu từ việc tải các thư mục phụ thuộc (ví dụ: quốc gia -> thành phố), kết thúc bằng việc kết hợp và xử lý thông tin với có nhiều nguồn(ví dụ: bạn đang sử dụng một số dịch vụ khác nhau, và mỗi người trong số họ dành thời điểm khác nhauđể tạo dữ liệu).

Và bây giờ đơn giản hơn một chút.

Sự cố khi tải dữ liệu không đồng bộ từng bước trong jQuery (ajax)

Nếu bạn cần kết nối một số yêu cầu ajax được thực hiện tuần tự trong jQuery thì hầu hết giải pháp đơn giản will - thực hiện cuộc gọi đến hàm sau vào cuối mỗi trình xử lý thành công. Điều này không chỉ khá đơn giản mà còn không gây ra bất kỳ vấn đề gì. Ví dụ,

// Yêu cầu đầu tiên $.ajax(url, ( ... thành công: function (kết quả) ( // Một số mã... // Gọi trình xử lý tiếp theo nextLoader(); ) ));

Và bây giờ, giả sử, trước mặt bạn đứng thêm một chút nhiệm vụ khó khăn. Ví dụ: bạn chỉ cần chạy một chức năng sau khi một số yêu cầu không đồng bộ đã hoàn thành (ví dụ: nhận bong bóng cho một trang web). Tất nhiên, chúng cũng có thể được kết nối thành một chuỗi thẳng, như hình trên. Tuy nhiên, cùng lúc đó, bản chất của sự không đồng bộ bắt đầu bị mất đi. Và cũng có thể bạn đang xây dựng sự phụ thuộc giữa các khối hoàn toàn không liên quan. Đồng ý rằng chỉ báo TCI và dữ liệu whois không hoàn toàn phụ thuộc vào nhau.

Tuy nhiên, bất chấp mọi sự tinh tế, một vấn đề như vậy có thể được giải quyết khá nhanh chóng, mặc dù hơi vụng về.

Nhưng bạn sẽ làm gì nếu nhiệm vụ của bạn trở nên khó khăn hơn? Khi bạn cần phân phối tất cả các hoạt động và tải dữ liệu thành các giai đoạn. Ví dụ: bạn đang tạo một mẫu hội thoại. Giai đoạn đầu tiên sẽ liên quan đến việc lấy dữ liệu cho tất cả các trường (danh sách thả xuống, nhóm hộp kiểm, v.v.). Ở giai đoạn thứ hai, trình xử lý cho các trường đã tạo sẽ được xác định. Và ở giai đoạn thứ ba, sau hết chỗ"mọi thứ và mọi thứ", quyền truy cập mở vào các nút khác nhau và các thành phần giao diện khác (để những bàn tay vui tươi không tạo ra nhiều vấn đề cho bạn). Về mặt trực quan, nó có thể trông như thế này:

Đồng ý rằng việc tổ chức các cuộc gọi của tất cả các chức năng trong một chuỗi không những không phải là một nhiệm vụ dễ dàng mà còn không mấy dễ chịu. Ngoài ra, hãy tưởng tượng rằng bạn cần thêm một số trường và các trình xử lý khác nhau. Chuyện gì sẽ xảy ra? Đầu của bạn sẽ bắt đầu sôi sục khi tìm kiếm đúng chỗ “chèn vào đâu”. Ở đây bạn đã cần một số loại cơ chế cho phép bạn sắp xếp tất cả các lần phóng theo từng giai đoạn.

Chúng tôi đang viết một tập lệnh để tổ chức tải không đồng bộ từng bước trong jQuery

Bước đầu tiên là quyết định câu hỏi hoàn toàn hợp lý "tại sao không sử dụng các thư viện làm sẵn?" Như vậy, không có câu trả lời cho câu hỏi này. Mọi thứ phụ thuộc rất nhiều vào nhiệm vụ. Vì từ "thư viện" thường có nghĩa là:

  • thiếu khả năng kiểm soát mã (bạn không thể thay đổi logic bên trong của thư viện; và nếu bạn làm điều này, thì mọi thay đổi có thể quay trở lại ám ảnh bạn trong tương lai)
  • sự cần thiết phải nghiên cứu nó Các tính chất cơ bản và các nguyên tắc (thông thường điều này phụ thuộc vào việc đọc tất cả các tài liệu có thể có và một loạt các bài kiểm tra khác nhau)
  • Hạn chế về phiên bản jQuery(nếu sử dụng các cơ chế hạt nhân phức tạp thì có thể liên kết với phiên bản của thư viện jQuery)
  • các vấn đề tương thích có thể xảy ra với các tập lệnh khác (không chắc chắn rằng thư viện sẽ hoạt động chính xác với các thư viện khác)
  • sự phong phú quá mức của chức năng và kết quả là sự hiện diện của “các hạn chế bổ sung”
  • vân vân.

Lưu ý: Đừng để bị lừa, vì các thư viện có số lượng lớnưu. Nếu bạn còn nhớ, jQuery cũng là thư viện tương tự. Bài viết tập trung vào những rủi ro và thời gian đầu tư bổ sung mà bạn có thể cần.

Đó là lý do tại sao trước tiên bạn phải quyết định về nhiệm vụ của mình (số lượng, tần suất xảy ra), thời gian (bạn sẵn sàng chi bao nhiêu để giải quyết vấn đề), bạn sẵn sàng hy sinh điều gì (là khả năng nhanh chóng sửa chữa điều gì đó quan trọng đối với bạn). ; kích thước của thư viện có quan trọng không; bao nhiêu? hạn chế phù hợp với bạn), sở thích (ví dụ: về cơ bản bạn không sử dụng thư viện). Và chỉ sau khi bạn trả lời những câu hỏi này, hãy cố gắng trả lời câu hỏi “tại sao việc sử dụng các thư viện làm sẵn lại đáng hoặc không đáng?”

Nếu bạn tự trả lời rằng bạn muốn sử dụng thư viện, thì, như một tùy chọn, bạn có thể tải xuống trường hợp thử nghiệm làm sẵn với tập lệnh tạo sẵn ở cuối bài viết.

Nếu bạn tràn đầy nhiệt huyết và quyết tâm thì chúng ta sẽ tiến hành những hành động tiếp theo.

Biên soạn yêu cầu cho kịch bản

Trước khi thực hiện bất cứ việc gì cũng cần đưa ra những yêu cầu nhỏ để không bị lạc đề trong quá trình thực hiện. Điều này dẫn đến một danh sách như thế này:

  • Việc kết nối và thiết lập tập lệnh sẽ diễn ra tự động (bạn chỉ cần kết nối tệp js)
  • Kết nối lại tệp tập lệnh sẽ không gây ra sự cố
  • Chỉ sử dụng các cơ chế jQuery tiêu chuẩn
  • Giao diện phải đơn giản và dễ hiểu
  • Bạn có thể tạo một số chuỗi giai đoạn độc lập
  • Bạn phải luôn có thể nhanh chóng điều chỉnh các hành động của tập lệnh
  • Tập lệnh không được áp đặt các hạn chế phức tạp đối với mã của bạn (tối đa - cần thêm chức năng thông báo về việc thực thi mã)

Lưu ý: Luôn xây dựng các yêu cầu để trong quá trình triển khai, bạn không bắt đầu làm điều gì đó không bắt buộc. Và hãy chắc chắn bao gồm những điểm “rất rõ ràng” trong đó, để những điểm này tiếp tục “rất rõ ràng”.

Lập dự án thử nghiệm

Cấu trúc dự án sẽ trông như thế này:

  • css - thư mục có kiểu
    • template.css - thử nghiệm kiểu dự án
  • hình ảnh - danh mục có hình ảnh (để tạo hiệu ứng hình ảnh)
    • ajax-loader.gif - tải hình ảnh
  • js - thư mục chứa tập lệnh
    • jquery-ajax-stage.js - tập lệnh để tải theo giai đoạn
  • data.json - dữ liệu thử nghiệm
  • index.html - trang chủ

Lưu ý: Khi tạo cấu trúc của dự án thử nghiệm, hãy cố gắng làm cho nó gần nhất có thể với cấu trúc của dự án thực. Điều này sẽ giúp bạn nắm bắt được các vấn đề liên quan đến cấu trúc trong quá trình phát triển.

Tệp có dữ liệu thử nghiệm - data.json

Tệp này chỉ cần thiết để đảm bảo rằng việc tải dữ liệu qua ajax sẽ không ảnh hưởng gì. Bạn có thể điền nó bằng bất kỳ json nào. Ví dụ như thế này:

( dữ liệu: "Rất nhiều dữ liệu")

Lưu ý: Cố gắng làm cho các trường hợp thử nghiệm giống nhất có thể với trường hợp thực tế. Ngay cả khi các lệnh gọi hàm là vô nghĩa.

Tệp kiểu - template.css

Tập tin này chỉ cần thiết để hiển thị tất cả các kiểu riêng biệt. Vì phong cách không liên quan gì đến sự phát triển của kịch bản. Có, và nó chỉ được coi là cách thực hành tốt. Bản thân các phong cách:

Bảng bên trái ( float: left; đệm-phải: 10px; ) .bảng bên phải ( float: left; đệm-phải: 10px; ) table.table-loader ( border-spacing: 0px; border-collapse: thu gọn; chiều rộng : 300px; ) table.table-loader tr td ( đệm: 5px; viền: 1px rắn #ccc; )

Tệp tập lệnh để tải không đồng bộ theo giai đoạn - jquery-ajax-stage.js

Việc thực hiện tải không đồng bộ từng bước.

(function (parentObject) ( // Bảo vệ chống lại việc định nghĩa lại if(parentObject.eventManager) return; // Xác định đối tượng parentObject.eventManager = ( // Thêm một giai đoạn addStage: function (el, stageName) ( var elCount = $( el).length; // Kiểm tra tính chính xác của các tham số if(elCount > 0 && !!stageName) ( // Một giai đoạn như vậy đã tồn tại if (($(el).get(0).eventStages = $(el) .get(0).eventStages || ())) return; // Xác định "nfg $(el).get(0).eventStages = ( WaiterCount: 0, // Bộ đếm các đối tượng trong trạng thái chờ dữ liệu onEvent: / / TRONG mảng này tất cả các chức năng được gọi sẽ được lưu trữ); ) ), // Xóa giai đoạn RemoveStage: function (el, stageName) ( var elCount = $(el).length; // Kiểm tra tính chính xác của các tham số if(elCount > 0 && !!stageName) ( // Như vậy giai đoạn được tìm thấy nếu (( $(el).get(0).eventStages = $(el).get(0).eventStages || ())) ( delete ($(el).get(0).eventStages = $(el).get (0).eventStages || ()); ($(el).get(0).eventStages = $(el).get(0).eventStages || ()) = null; ) ) ), // Tăng bộ đếm của các hàm được thực thi cho giai đoạn addStageWaiter: function (el, stageName) ( var elCount = $(el).length, stage = ($(el).get(0).eventStages = $(el) ).get(0).eventStages || ()); // Kiểm tra tính chính xác của các tham số if(elCount > 0 && !!stageName && stage) ( // Tăng bộ đếm tải stage.waiterCount++; ) ), // Giảm bộ đếm của các hàm được thực thi cho giai đoạn // Tức là. thông báo rằng hàm đã được thực thi RemoveStageWaiter: function (el, stageName) ( var elCount = $(el).length, stage = ($(el).get(0).eventStages = $(el).get(0) .eventStages || ()); // Kiểm tra tính đúng đắn của các tham số if(elCount > 0 && !!stageName && stage) ( // Giảm bộ đếm tải stage.waiterCount--; // Kiểm tra trạng thái của giai đoạn này .checkStage(el, stageName); ) ), // Kiểm tra trạng thái của giai đoạn checkStage: function (el, stageName) ( var elCount = $(el).length, stage = ($(el).get(0) .eventStages = $(el).get(0) .eventStages || ()); // Kiểm tra tính chính xác của các tham số if(elCount > 0 && !!stageName && stage) ( if (stage.waiterCount 0) ( / / Hàng đợi FIFO - vào trước, ra trước, như trong kho giai đoạn. onEvent.shift())(; ) ) ) ), // Thêm lệnh gọi hàm sẽ chạy khi toàn bộ giai đoạn onLoadStage được thực thi: function (el, stageName, funcHandler) ( var elCount = $(el).length, stage = ($ (el).get(0).eventStages = $(el).get(0).eventStages || ()); // Kiểm tra các tham số đều đúng if(elCount > 0 && !!stageName && stage && typeof (funcHandler) = == "function") ( // Thêm trình xử lý stage.onEvent.push(funcHandler); // Kiểm tra trạng thái của stage this.checkStage(el, stageName); ) ) ); ))(cửa sổ);

Trang thử nghiệm - index.html

Trang thử nghiệm khá lớn (khoảng 160 dòng), vì vậy chỉ một phần mã sẽ được cung cấp. Phiên bản đầy đủ bạn luôn có thể tìm thấy tệp trong kho lưu trữ zip.

Chúng tôi bao gồm tất cả các tập tin cần thiết:

Hãy tạo một vài khối thử nghiệm. Khối bao gồm nút khởi chạy và bảng nơi dữ liệu sẽ được ghi lại từng bước.

Bắt đầu tải xuống

Hãy xác định một hàm sẽ tạo các hàm kiểm tra cho các giai đoạn:

function getFakeLoader(storage, currStage, startDate, selector) ( return function () ( setTimeout(function () ( $.ajax("data.json?callback=?", ( contentType: "text/plain; charset=utf-8 ", dataType: "jsonp", jsonpCallback: function (kết quả) ( $(selector).html("Thời gian từ khi bắt đầu: " + ((+new Date() - startDate)/1000.0).toFixed(2) + " giây "); // Viết thời gian tải window.eventManager.removeStageWaiter(storage, currStage); // Giảm bộ đếm ) )); ), Math.random() * (3000) + 1000 // Delay từ 1 đến 4 giây ); ); )

Chúng tôi tạo một hàm mô tả logic cho từng khối kiểm tra:

function formTestFor(selector) ( $(selector + " .start-process").click(function () ( var startDate = new Date(); // Để đẹp hơn, hãy thêm ảnh setLoaderImgs(selector); // Xác định cửa sổ giai đoạn .eventManager .addStage($(selector + " .table-loader"), "1"); window.eventManager.addStage($(selector + " .table-loader"), "2"); window.eventManager.addStage ($ (selector + " .table-loader"), "3"); // Chặn nút cho đến hết giai đoạn $(selector + " .start-process").attr("disabled", "disabled" ); // Lấp đầy hàng đợi chờ 3 lần tải cho mỗi giai đoạn // Trên thực tế, những hành động này sẽ xảy ra ở những nơi mà các chức năng của giai đoạn được khởi chạy window.eventManager.addStageWaiter($(selector + " .table-loader"), "1 "); ... window.eventManager.addStageWaiter ($(selector + " .table-loader"), "3"); // Bây giờ hãy tạo trong thứ tự ngược lại(để rõ ràng) tải hàm // Trên thực tế, những hành động này sẽ xảy ra ở những nơi mà hàm được xác định window.eventManager.onLoadStage($(selector + " .table-loader"), "2", getFakeLoader($(selector + " .table-loader"), "3", startDate, selector + " .row-3 .td-1")); ... window.eventManager.onLoadStage($(selector + " .table-loader"), "1", getFakeLoader($(selector + " .table-loader"), "2", startDate, selector + " .row -2 .td-3")); // Thêm một đầu ra văn bản thông thường của các giai đoạn đã hoàn thành window.eventManager.onLoadStage($(selector + " .table-loader"), "1", function () ( $(selector + " .row-1-end td" .html ("Giai đoạn đầu tiên kết thúc sau " + ((+new Date() - startDate)/1000.0).toFixed(2) + " giây. Giai đoạn tiếp theo bắt đầu."); )); ... window.eventManager.onLoadStage($(selector + " .table-loader"), "3", function () ( $(selector + " .row-3-end td").html("Giai đoạn thứ ba đã kết thúc trong " + ((+new Date() - startDate)/1000.0).toFixed(2) + " giây.
Quá trình tải hoàn tất"); )); // Sau khi hoàn thành giai đoạn thứ ba, hãy mở khóa nút onLoadStage window.eventManager.onLoadStage($(selector + " .table-loader"), "3", function () ( // Mở khóa nút $(selector + " .start-process").attr("disabled", null); )); // Bây giờ hãy chạy các chức năng của giai đoạn đầu tiên getFakeLoader($(selector + " .table-loader") , "1", startDate, bộ chọn + " .row-1 .td-1")(); getFakeLoader($(selector + " .table-loader"), "1", startDate, bộ chọn + " .row-1 .td-2")()); getFakeLoader($(selector + " .table-loader"), "1", startDate, selector + " .row-1 .td-3")(); // Quan sát.. . )); )

Bây giờ chúng tôi thu thập tất cả các tệp vào dự án và chuyển sang thử nghiệm và trình diễn ban đầu.

Hãy xem kết quả

Mở tệp index.html trong trình duyệt. Giao diện sau sẽ được hiển thị:

Như bạn có thể thấy, chúng tôi có sẵn hai nút để khởi chạy các quy trình song song. Sau khi nhấp vào chúng, quá trình tải xuống các khối tương ứng sẽ bắt đầu. Và nó sẽ trông giống như thế này:

Sau khi cả hai quá trình đã hoàn tất quá trình thực thi, hãy xem thời gian và đảm bảo rằng các giai đoạn diễn ra theo đúng thứ tự:

Sau khi hoàn thành thử nghiệm ban đầu, chúng tôi chuyển sang kiểm tra các yêu cầu:

  • Việc kết nối và thiết lập tập lệnh sẽ diễn ra tự động (bạn chỉ cần kết nối tệp js) - Có
  • Việc kết nối lại tệp tập lệnh sẽ không gây ra sự cố - Có
  • Chỉ sử dụng các cơ chế jQuery tiêu chuẩn - Có (chỉ sử dụng chức năng bộ chọn)
  • Giao diện phải đơn giản và dễ hiểu - Có
  • Bạn có thể tạo một số chuỗi giai đoạn độc lập - Có
  • Bạn luôn có thể nhanh chóng sửa các hành động của tập lệnh - Có (tập lệnh được viết khá đơn giản; phần chính bao gồm kiểm tra dữ liệu đầu vào)
  • Tập lệnh không được áp đặt các hạn chế phức tạp đối với mã của bạn (tối đa - cần thêm chức năng để thông báo về việc hoàn thành của nó) - Có (bên trong các hàm getFakeLoader, chỉ có chức năng thông báo về việc hoàn thành của nó được gọi)

Giờ đây, bạn đã có một tập lệnh đơn giản và rõ ràng giúp bạn nhanh chóng sắp xếp việc thực thi các chức năng theo từng bước, có thể là tải dữ liệu hoặc đơn giản là thực hiện các thao tác.

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 Google PageSpeed ​​​​Insights khuyên bạn nên xóa khỏi đầu trang Mã JavaScript, chặn hiển thị của nó. 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 tập tin riêng biệt và 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 hết chúng ta hãy nhìn vào trình tự xử lý tài liệu khi kết nối bình thường thẻ kịch bản.

1 < src = "example.js" >

TRONG ví dụ rõ ràng Tôi sẽ sử dụng như sau biểu tượng:

- 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. Chúng được thực thi sau phân tích đầy đủ mô hình đối tượng tài liệu (từ Tài liệu tiếng Anh Mô hình đối tượng, viết tắt DOM), với trình duyệt đảm bảo tính nhất quán dựa trên thứ tự các tệp được đưa vào.

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 quầy thu thập số liệu thống kê ( Google phân tích, Yandex Metrica), mã mạng quảng cáo (Mạng quảng cáo Yandex, Google Adsense), nút mạng xã hội và như thế.

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

Không đồng bộ Kết nối JavaScript Giảm thời gian tải trang do không có độ 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 😎

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 không đồng bộ tập lệnh như Google/Adsense thực hiện điều đó

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 đó lợi dụng những khuyến nghị sau đây. Đây thực chất là lười tải. Vì lệnh gọi tập lệnh thực sự xảy ra ở cuối trang HTML, tức 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ông việc JavaScript bạn cần tạo một khối div trống:

Sau đó ở cuối trang trước khi kết thúc gắn thẻ CƠ THỂ chèn tập lệnh để tải không đồng bộ:

// JavaScript cần được tải không đồng bộ // di chuyển nó tới vị trí thực hiển thị 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ư trình duyệt web IE 6. May mắn thay, điều này hầu như không bao giờ được tìm thấy trên máy tính của 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 kết xuất 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 Tệp JavaScript 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 như tập tin bên ngoài có thuộc tính này, 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ư 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ậy khi nào bạn nên sử dụng không đồng bộ, hoãn lại hay bình thường? Thực thi JavaScript? 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 cú pháp 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 các tệp JavaScript phải được giảm thiểu theo mặc định.

Lý do viết bài này là vì đã hơn một lần tôi nhận thấy việc chèn mã nút vào một trang dịch vụ khác nhau(ví dụ: VKontakte, Facebook, Twitter, Odnoklassniki) đã dẫn đến tốc độ tải và hiển thị trang chậm lại đáng kể. Đó là về về trường hợp sử dụng javascript bên ngoài của các dịch vụ xã hội này.
Nếu chúng ta sử dụng tĩnh đơn giản nút đồ họa, không có vấn đề gì, bởi vì Đây là mức tối thiểu của đồ họa và tập lệnh được đặt cục bộ (bạn có thể xem ví dụ về cách triển khai tại đây http://pervushin.com/social-button-for-blog.html). Nhưng chúng ta chỉ nhìn thấy các biểu tượng xã hội. dịch vụ, không có số liệu thống kê (có bao nhiêu người “thích” trang của chúng tôi). Những thứ kia. nếu muốn xem số liệu thống kê, chúng ta sẽ phải kết nối các tập lệnh bên ngoài. Và ở đây, điều cần lưu ý là chúng ta đã kết nối bao nhiêu nút trong số này thì trình duyệt buộc phải tải xuống rất nhiều tập lệnh bên ngoài, tức là. Cái này kết nối bổ sung tới các máy chủ bên ngoài.

Để hiển thị điều gì sẽ xảy ra nếu có tập lệnh trong phần trên trang, tôi đề xuất xem xét một số ví dụ thử nghiệm. Tôi sẽ sử dụng FireFox 3.6 và FireBug.

Vì thế:
1) Trang đơn giản nhất với một tệp kiểu, hai tập lệnh và ba hình ảnh:













Và đây là sơ đồ tải cho nó:

Xin lưu ý rằng tất cả hình ảnh chỉ được tải sau khi tệp javascript dài nhất được tải.
Tôi đã cố tình tải dummy_css.css và dummy_js.js khá lâu. Đó chỉ là hai tập tin:

dummy_css.php

html,nội dung(
lề:0;
phần đệm: 0;
}
.img_container(
lề:0 tự động;chiều rộng:500px;
}

dummy_js.php


var param=1;

Vì vậy, bạn có thể thấy rằng tệp js chặn tải tất cả các đồ họa khác.

2) Mọi thứ gần như giống nhau, ngoại trừ dummy_js. js được tải từ máy chủ bên ngoài:

Tình huống tương tự như lần trước:

3) Hãy thử hoán đổi các tệp css và js trong phần đầu (css hiện đứng sau js):







Hãy nhìn vào sơ đồ tải:

Js vẫn chặn tải hình ảnh, bất kể nó được tải từ máy chủ nào.

4) Hãy tăng thời gian tải css lên 4 giây (mã html như trong trường hợp N3):

5) Một trường hợp thú vị khác: css được đặt trước js, nhưng css mất nhiều thời gian hơn để tải















Ở đây css đã chặn việc tải hình ảnh...

6) Di chuyển một js vào trong< body>
















Có thể thấy rằng dummy_ js. js chỉ chặn tải hình ảnh thứ ba, nằm trong mã html sau nó. Nhưng nếu css tải lâu hơn thì nó sẽ chặn tải đồ họa. Không khó để tưởng tượng rằng việc cắm vào các tập lệnh bên ngoài có thể làm chậm quá trình tải và hiển thị trang rất nhiều, đặc biệt nếu máy chủ từ xa Vì lý do nào đó phải mất một thời gian dài để phản hồi.

Đặt các tập lệnh bên ngoài trước

Điều gì ngay lập tức gợi ý... Tất cả các tập lệnh có tải không quan trọng đối với trang phải được đặt ngay trước thẻ đóng. Nhưng điều này có thể được thực hiện đối với những tập lệnh trong đó tất cả logic là bên trong và không có lệnh gọi bên ngoài nào từ Mã HTML. Nếu từ mã html, một số hàm được gọi từ các tập lệnh chưa được tải thì những tình huống đó phải được xử lý theo cách đặc biệt, bởi vì bạn cần theo dõi quá trình tải xuống.

Nhưng có một vấn đề khác, hãy để tôi giải thích bằng một ví dụ:




$("img").click(function() (
cảnh báo($(this).attr("src"));
});
});






Nếu js trước đó tải lâu thì nhấp vào ảnh cho đến khi tập lệnh này được tải đầy đủ sẽ không dẫn đến bất cứ điều gì, bởi vì $(document).ready() sẽ chỉ hoạt động sau khi js được tải đầy đủ. Vì vậy, nếu có một số logic trên các trang liên quan đến việc xử lý sự kiện thì phương pháp này không phù hợp.

Vì vậy, điều cần thiết là một cách để tải tập lệnh mà không bị chặn...

Tạo async.js:



script.src = "dummy_js.js";


và kết nối nó:











$(document).ready(function() (
$("img").click(function() (
cảnh báo($(this).attr("src"));
});
});






Nếu lệnh gọi async.js được đặt trong , chứ không phải trước , thì sơ đồ sẽ trông như thế này:

Nhưng nếu việc đặt async.js vào mã vẫn thuận tiện hơn, thì bạn nên thay đổi một chút nội dung của async.js:

$(document).ready(function() (
var script = document.createElement("script");
script.src = "dummy_js.js";
document.getElementsByTagName("head") .appendChild(script);
}
);

Vì vậy, vấn đề tải không đồng bộ đã được giải quyết nhưng vấn đề đồng bộ hóa việc tải các tập lệnh bên ngoài và mã sử dụng chúng vẫn còn bỏ ngỏ. Hãy xem xét nó trong thực tế, kết nối các nút mạng xã hội.