Nếu bạn không tự động tải tập lệnh hoặc đánh dấu chúng là defer
hoặc async
, thì tập lệnh được tải theo thứ tự gặp phải trong trang. Không quan trọng đó là tập lệnh bên ngoài hay tập lệnh nội tuyến - chúng được thực thi theo thứ tự chúng gặp trong trang. Các tập lệnh nội tuyến xuất hiện sau các tập lệnh bên ngoài được giữ cho đến khi tất cả các tập lệnh bên ngoài xuất hiện trước khi chúng được tải và chạy.
Các tập lệnh async (bất kể chúng được chỉ định là async như thế nào) tải và chạy theo thứ tự không thể đoán trước. Trình duyệt tải chúng song song và có thể tự do chạy chúng theo bất kỳ thứ tự nào nó muốn.
Không có thứ tự dự đoán trong số nhiều thứ không đồng bộ. Nếu ai đó cần một thứ tự dự đoán, thì nó sẽ phải được mã hóa bằng cách đăng ký thông báo tải từ các tập lệnh async và sắp xếp các lệnh gọi javascript theo cách thủ công khi những thứ thích hợp được tải.
Khi thẻ script được chèn động, cách thức thực hiện lệnh sẽ phụ thuộc vào trình duyệt. Bạn có thể thấy Firefox hoạt động như thế nào trong bài viết tham khảo này . Tóm lại, các phiên bản mới hơn của Firefox mặc định thẻ script được thêm động vào async trừ khi thẻ script được đặt khác.
Thẻ script có async
thể được chạy ngay khi được tải. Trong thực tế, trình duyệt có thể tạm dừng trình phân tích cú pháp từ bất cứ điều gì khác mà nó đang làm và chạy tập lệnh đó. Vì vậy, nó thực sự có thể chạy bất cứ lúc nào. Nếu tập lệnh được lưu trữ, nó có thể chạy gần như ngay lập tức. Nếu tập lệnh mất một lúc để tải, nó có thể chạy sau khi trình phân tích cú pháp hoàn tất. Một điều cần nhớ async
là nó có thể chạy bất cứ lúc nào và thời gian đó là không thể dự đoán được.
Thẻ script defer
chờ đợi cho đến khi toàn bộ trình phân tích cú pháp được thực hiện và sau đó chạy tất cả các tập lệnh được đánh dấu theo defer
thứ tự chúng gặp phải. Điều này cho phép bạn đánh dấu một số tập lệnh phụ thuộc lẫn nhau như defer
. Tất cả họ sẽ bị hoãn lại cho đến sau khi trình phân tích cú pháp tài liệu được thực hiện, nhưng họ sẽ thực hiện theo thứ tự họ gặp phải để duy trì sự phụ thuộc của họ. Tôi nghĩ defer
giống như các tập lệnh được thả vào hàng đợi sẽ được xử lý sau khi trình phân tích cú pháp hoàn tất. Về mặt kỹ thuật, trình duyệt có thể tải xuống các tập lệnh ở chế độ nền bất cứ lúc nào, nhưng chúng sẽ không thực thi hoặc chặn trình phân tích cú pháp cho đến khi trình phân tích cú pháp hoàn tất phân tích trang và phân tích cú pháp và chạy bất kỳ tập lệnh nội tuyến nào không được đánh dấu defer
hoặc async
.
Đây là một trích dẫn từ bài viết đó:
tập lệnh được chèn tập lệnh thực thi không đồng bộ trong IE và WebKit, nhưng đồng bộ trong Opera và Firefox trước 4.0.
Phần có liên quan của thông số HTML5 (dành cho các trình duyệt tuân thủ mới hơn) có tại đây . Có rất nhiều điều được viết trong đó về hành vi không đồng bộ. Rõ ràng, thông số kỹ thuật này không áp dụng cho các trình duyệt cũ hơn (hoặc các trình duyệt không phù hợp) có hành vi mà bạn có thể phải kiểm tra để xác định.
Một trích dẫn từ thông số HTML5:
Sau đó, các tùy chọn đầu tiên sau đây mô tả tình huống phải được tuân theo:
Nếu phần tử có thuộc tính src và phần tử có thuộc tính defer và phần tử đã được gắn cờ là "trình phân tích cú pháp được chèn" và phần tử không có thuộc tính async
Phần tử phải được thêm vào cuối danh sách các tập lệnh sẽ thực thi khi tài liệu đã phân tích xong liên kết với Tài liệu của trình phân tích cú pháp đã tạo ra phần tử.
Tác vụ mà nguồn tác vụ mạng đặt trên hàng đợi tác vụ khi thuật toán tìm nạp đã hoàn thành phải đặt cờ "sẵn sàng để được phân tích cú pháp" của phần tử. Trình phân tích cú pháp sẽ xử lý việc thực thi tập lệnh.
Nếu phần tử có thuộc tính src và phần tử đã được gắn cờ là "trình phân tích cú pháp được chèn" và phần tử không có thuộc tính async
Phần tử là tập lệnh chặn phân tích cú pháp đang chờ xử lý của Tài liệu của trình phân tích cú pháp đã tạo phần tử. (Mỗi lần chỉ có thể có một tập lệnh như vậy cho mỗi Tài liệu.)
Tác vụ mà nguồn tác vụ mạng đặt trên hàng đợi tác vụ khi thuật toán tìm nạp đã hoàn thành phải đặt cờ "sẵn sàng để được phân tích cú pháp" của phần tử. Trình phân tích cú pháp sẽ xử lý việc thực thi tập lệnh.
Nếu phần tử không có thuộc tính src và phần tử đã được gắn cờ là "trình phân tích cú pháp được chèn" và Tài liệu của trình phân tích cú pháp HTML hoặc trình phân tích cú pháp XML đã tạo phần tử tập lệnh có một biểu định kiểu đang chặn các tập lệnh Phần tử là tập lệnh chặn phân tích cú pháp đang chờ xử lý của Tài liệu của trình phân tích cú pháp đã tạo phần tử. (Mỗi lần chỉ có thể có một tập lệnh như vậy cho mỗi Tài liệu.)
Đặt cờ "sẵn sàng để được phân tích cú pháp" của phần tử. Trình phân tích cú pháp sẽ xử lý việc thực thi tập lệnh.
Nếu phần tử có thuộc tính src, không có thuộc tính async và không có bộ cờ "force-async" Phần tử phải được thêm vào cuối danh sách các tập lệnh sẽ thực hiện theo thứ tự càng sớm càng tốt với Tài liệu của phần tử tập lệnh tại thời điểm chuẩn bị thuật toán tập lệnh.
Tác vụ mà nguồn tác vụ mạng đặt trên hàng đợi tác vụ khi thuật toán tìm nạp đã hoàn thành phải chạy các bước sau:
Nếu phần tử bây giờ không phải là phần tử đầu tiên trong danh sách các tập lệnh sẽ thực thi theo thứ tự càng sớm càng tốt, thì đánh dấu phần tử là đã sẵn sàng nhưng hủy bỏ các bước này mà không thực thi tập lệnh.
Thực thi: Thực thi khối tập lệnh tương ứng với phần tử tập lệnh đầu tiên trong danh sách tập lệnh này sẽ thực hiện theo thứ tự càng sớm càng tốt.
Xóa phần tử đầu tiên khỏi danh sách các tập lệnh này sẽ thực thi theo thứ tự càng sớm càng tốt.
Nếu danh sách các tập lệnh này sẽ thực thi theo thứ tự càng sớm càng tốt vẫn không trống và mục nhập đầu tiên đã được đánh dấu là đã sẵn sàng, sau đó quay lại bước thực hiện có nhãn.
Nếu phần tử có thuộc tính src Phần tử phải được thêm vào tập lệnh sẽ thực thi càng sớm càng tốt đối với Tài liệu của phần tử tập lệnh tại thời điểm chuẩn bị thuật toán tập lệnh.
Tác vụ mà nguồn tác vụ mạng đặt trên hàng đợi tác vụ khi thuật toán tìm nạp đã hoàn thành phải thực thi khối tập lệnh và sau đó xóa phần tử khỏi bộ tập lệnh sẽ thực thi càng sớm càng tốt.
Nếu không Các user agent phải thực hiện ngay lập tức khối kịch bản, ngay cả khi kịch bản khác đã được thực hiện.
Còn các kịch bản mô-đun Javascript thì type="module"
sao?
Javascript hiện có hỗ trợ tải mô-đun với cú pháp như thế này:
<script type="module">
import {addTextToBody} from './utils.mjs';
addTextToBody('Modules are pretty cool.');
</script>
Hoặc, với src
thuộc tính:
<script type="module" src="http://somedomain.com/somescript.mjs">
</script>
Tất cả các tập lệnh với type="module"
được tự động đưa ra defer
thuộc tính. Điều này tải chúng song song (nếu không phải là nội tuyến) với việc tải trang khác và sau đó chạy chúng theo thứ tự, nhưng sau khi trình phân tích cú pháp hoàn tất.
Các tập lệnh mô-đun cũng có thể được cung cấp async
thuộc tính sẽ chạy các tập lệnh mô-đun nội tuyến càng sớm càng tốt, không phải đợi cho đến khi trình phân tích cú pháp hoàn thành và không chờ chạy async
tập lệnh theo bất kỳ thứ tự cụ thể nào so với các tập lệnh khác.
Có một biểu đồ dòng thời gian khá hữu ích cho thấy tìm nạp và thực thi các tổ hợp tập lệnh khác nhau, bao gồm các tập lệnh mô-đun ở đây trong bài viết này: Đang tải Mô-đun Javascript .