Làm thế nào chính xác là <script defer = trong thời gian trì hoãn> hoạt động?


208

Tôi có một vài <script>yếu tố và mã trong một số <script>yếu tố phụ thuộc vào mã trong các yếu tố khác . Tôi thấy deferthuộc tính có thể có ích ở đây vì nó cho phép các khối mã được hoãn lại trong thực thi.

Để kiểm tra, tôi đã thực hiện điều này trên Chrome: http://jsfiddle.net/xXZMN/ .

<script defer="defer">alert(2);</script>
<script>alert(1)</script>
<script defer="defer">alert(3);</script>

Tuy nhiên, nó cảnh báo 2 - 1 - 3. Tại sao nó không cảnh báo 1 - 2 - 3?


2
Có thể kiểm tra bài viết này . Và, như mọi khi, IE tự chịu trách nhiệm về điều gì đó và quyết định tải tập lệnh trước nhưng trì hoãn thực thi cho đến khi phần thân được tải (thông thường).
Brad Christie

Tuy nhiên, cảm ơn, trang thử nghiệm có kết quả khác trên Chrome: websiteoptimization.com/speed/tweak/defer/test . Ảnh chụp màn hình cho thấy tôi mong đợi như thế nào, trong khi Chrome dường như chỉ thực hiện việc trì hoãn trước.
pimvdb

1
Tôi nghĩ rằng bạn sẽ tìm thấy định nghĩa về trì hoãn của IE, phù hợp với ý định của W3C về trì hoãn trong thông số DOM Cấp 1.
Đánh dấu tại Ramp51

41
Như Alohci đã chỉ ra trong câu trả lời của mình, theo Tiêu chuẩn HTML defer chỉ có giá trị khi chỉ định src. Đây có thể là một lý do tại sao ví dụ của bạn không hoạt động như mong đợi trong hầu hết các trình duyệt.
Pankrat

2
@Pankrat Chuyện thật! Hãy thử jsfiddle.net/xXZMN/50 Đã thử nghiệm trong Firefox24
m93a

Câu trả lời:


51

CẬP NHẬT: 19/2/2016

Xem xét câu trả lời này đã lỗi thời. Tham khảo các câu trả lời khác trên bài đăng này để biết thông tin liên quan đến phiên bản trình duyệt mới hơn.


Về cơ bản, defer bảo trình duyệt đợi "cho đến khi nó sẵn sàng" trước khi thực thi javascript trong khối tập lệnh đó. Thông thường, đây là sau khi DOM tải xong và document. YetState == 4

Thuộc tính defer dành riêng cho internet explorer. Trong Internet Explorer 8, trên Windows 7, kết quả mà tôi đang thấy trong trang thử nghiệm JS Fiddle của bạn là, 1 - 2 - 3.

Các kết quả có thể khác nhau tùy theo trình duyệt.

http://msdn.microsoft.com/en-us/l Library / ms533719 (v = vs85) .aspx

Trái với niềm tin phổ biến, IE tuân theo các tiêu chuẩn thường xuyên hơn mọi người, trên thực tế, thuộc tính "defer" được định nghĩa trong thông số DOM Cấp 1 http://www.w3.org/TR/REC-DOM-Level-1/level -one-html.html

Định nghĩa của W3C về defer: http://www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer :

"Khi được đặt, thuộc tính boolean này cung cấp một gợi ý cho tác nhân người dùng rằng tập lệnh sẽ không tạo ra bất kỳ nội dung tài liệu nào (ví dụ: không có" document.write "trong javascript) và do đó, tác nhân người dùng có thể tiếp tục phân tích cú pháp và kết xuất."


8
@ MarkAtRamp51 - Nếu câu trả lời của bạn đã lỗi thời, bạn nên chỉnh sửa nó thay vì phàn nàn về những lời bình luận trong các bình luận về các câu trả lời khác. Downvote là cho câu trả lời "không hữu ích."
Christian Conkle 28/03/2015

10
@ChristianConkle Tôi đánh giá cao bài học về nghi thức, tuy nhiên các câu trả lời khác ở đây được cập nhật. Tôi đã giải quyết một thực tế là câu trả lời sai không được chọn vào thời điểm câu hỏi được hỏi. Có lẽ bạn nên cảnh sát những người lan truyền những đánh giá sai lệch về cộng đồng lựa chọn câu trả lời không đúng, thay vì những người cố gắng nhắc nhở mọi người rằng mọi thứ thay đổi theo thời gian và bối cảnh là quan trọng. Tôi không thấy giá trị trong việc loại bỏ câu trả lời của mình vì thông tin lịch sử cũng có giá trị.
Đánh dấu tại Ramp51

3
"Tôi không thấy giá trị trong việc xóa câu trả lời của mình vì thông tin lịch sử cũng có giá trị" Trong trường hợp đó, cách thêm một ghi chú vào đầu chỉ ra rằng nó chỉ áp dụng cho tiền HTML5, sau đó liên kết với "chính xác" ( cập nhật) câu trả lời? Điều đó sẽ giúp bạn tiết kiệm rất nhiều rắc rối (nói như một chàng trai cũng có câu trả lời "sai" được chấp nhận một lần và "bị áp lực ngang hàng" để cuối cùng thay đổi nó).
mgibsonbr

3
@Leo có nên đánh cờ không? Bằng cách tìm kiếm "html5 defer script", đây là kết quả thứ ba trong google. Câu trả lời này sau đó đang cung cấp rất nhiều người dùng với định nghĩa lỗi thời và không chính xác. (Định nghĩa hiện tại: "Cho biết tác nhân người dùng có thể trì hoãn xử lý tập lệnh. Xem định nghĩa thuộc tính của trình trì hoãn trong HTML 4.0.").
Malavos

2
@ MarkAtRamp51I nghĩ bạn nên cập nhật câu trả lời của mình. Bất cứ ai tìm thấy câu hỏi này và vì vậy câu trả lời của bạn sẽ không nhận ra thông tin lịch sử của nó. Nó sẽ xem xét cho họ như đó là câu trả lời đúng trong ngày hôm nay. Đó là cách internet hoạt động. Vì vậy, bạn nên chỉnh sửa câu trả lời của mình, lưu ý rằng nó đã đúng một lần và tham khảo câu trả lời đúng.
Juuro

167

Một vài đoạn trích từ thông số HTML5: http://w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async

Các thuộc tính defer và async không được chỉ định nếu không có thuộc tính src.


Có ba chế độ có thể được chọn bằng các thuộc tính này [async và defer]. Nếu thuộc tính async có mặt, thì tập lệnh sẽ được thực thi không đồng bộ, ngay khi có sẵn. Nếu thuộc tính async không có nhưng thuộc tính defer có mặt, thì tập lệnh được thực thi khi trang đã phân tích xong. Nếu không có thuộc tính nào, thì tập lệnh được tìm nạp và thực thi ngay lập tức, trước khi tác nhân người dùng tiếp tục phân tích trang.


Các chi tiết xử lý chính xác cho các thuộc tính này, chủ yếu là vì lý do lịch sử, hơi không tầm thường, liên quan đến một số khía cạnh của HTML. Do đó, các yêu cầu thực hiện là do sự cần thiết nằm rải rác trong đặc tả. Các thuật toán bên dưới (trong phần này) mô tả cốt lõi của quá trình xử lý này, nhưng các thuật toán này tham chiếu và được tham chiếu bởi các quy tắc phân tích cú pháp cho các thẻ bắt đầu và kết thúc tập lệnh trong HTML, trong nội dung nước ngoài và trong XML, các quy tắc cho document.write () phương thức, xử lý kịch bản, v.v.


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 đã hoàn thành phân tích cú pháp được liên kết với Tài liệu của trình phân tích cú pháp đã tạo phần tử.


37
Có lẽ, phản hồi của tôi ở đây sẽ ngăn mọi người từ chối bình chọn câu trả lời của tôi, do nhận xét không hữu ích của bạn. Câu trả lời được chấp nhận không sai, câu trả lời là khác nhau, bởi vì vào đầu năm 2011, thông số HTML5 ít liên quan đến các webbrows chính hơn so với hiện tại. Câu trả lời này có thể tốt hơn về phía trước, nhưng câu trả lời được chấp nhận không SAI theo bất kỳ tiêu chuẩn nào.
Đánh dấu tại Ramp51

3
Mặc dù rất hữu ích khi biết thông số kỹ thuật nói gì, nhưng hóa ra một số trình duyệt như IE <9 thực hiện không defertốt . Nếu bạn sử dụng defer, bạn không thể dựa vào các tệp script được thực thi theo thứ tự trong một số trình duyệt.
Flimm


Câu nói đầu tiên không còn giá trị nữa phải không? Bây giờ tôi có thể đọc điều này: "Không được chỉ định thuộc tính nếu không có thuộc tính src hoặc nếu tập lệnh không phải là tập lệnh cổ điển.". Và một tập lệnh cổ điển là tập lệnh không có src = "".
Félix Sanz

158

Câu trả lời thực sự là: Bởi vì bạn không thể tin tưởng vào việc trì hoãn.

Về khái niệm, defer và async khác nhau như sau:

async cho phép tập lệnh được tải xuống trong nền mà không bị chặn. Sau đó, thời điểm nó hoàn tất tải xuống, kết xuất sẽ bị chặn và tập lệnh đó thực thi. Kết xuất lại khi kịch bản đã thực thi.

defer thực hiện điều tương tự, ngoại trừ các yêu cầu để đảm bảo rằng các tập lệnh thực thi theo thứ tự chúng được chỉ định trên trang và chúng sẽ được thực thi sau khi tài liệu đã phân tích xong. Vì vậy, một số tập lệnh có thể hoàn tất tải xuống, sau đó ngồi và đợi tập lệnh tải xuống sau nhưng xuất hiện trước chúng.

Thật không may, do thực sự là một cuộc chiến mèo tiêu chuẩn, định nghĩa của defer thay đổi thông số kỹ thuật và thậm chí trong các thông số kỹ thuật gần đây nhất không cung cấp một đảm bảo hữu ích. Như câu trả lời ở đâyvấn đề này chứng minh, các trình duyệt thực hiện trì hoãn khác nhau:

  • Trong một số trường hợp nhất định, một số trình duyệt có lỗi khiến defertập lệnh bị lỗi .
  • Một số trình duyệt trì hoãn DOMContentLoadedsự kiện cho đến khi defertập lệnh được tải và một số trình duyệt thì không.
  • Một số trình duyệt vâng lời defertrên <script>các yếu tố với mã nội tuyến và không có một srcthuộc tính, và một số bỏ qua nó.

May mắn là thông số kỹ thuật ít nhất chỉ định rằng async ghi đè lên defer. Vì vậy, bạn có thể coi tất cả các tập lệnh là không đồng bộ và nhận được rất nhiều hỗ trợ trình duyệt như vậy:

<script defer async src="..."></script>

98% trình duyệt được sử dụng trên toàn thế giới và 99% ở Hoa Kỳ sẽ tránh bị chặn với phương pháp này.

(Nếu bạn cần đợi cho đến khi tài liệu phân tích xong, hãy lắng nghe sự DOMContentLoadedkiện hoặc sử dụng .ready()chức năng tiện dụng của jQuery . Dù sao bạn cũng muốn làm điều này để trở lại duyên dáng trên các trình duyệt hoàn toàn không thực hiện defer.)


13
Cảm ơn, câu trả lời của bạn là hữu ích nhất cho tôi!
markus

5
Tôi tin rằng điều này là không chính xác. Lợi ích của việc trì hoãn là nó không thực thi cho đến khi phân tích trang hoàn tất. Trang này có một hình ảnh tốt để giải thích sự khác biệt giữa async và defer
tinkerr

1
@tinkerr Trong khái niệm bạn đúng; trong thực tế điều này không trở thành sự thật. Bởi vì nó không được thực hiện một cách nhất quán, bảo đảm trình tự không phải là phổ quát, và do đó, không phải là bảo đảm. Khi thực hiện một cái gì đó bạn quan tâm về việc thực hiện. Mục đích của thiết kế là dễ thương, nhưng, không đặc biệt hữu ích.
Chris Moschini

Chỉ muốn chỉ ra rằng Opera đã hỗ trợ deferthuộc tính kể từ phiên bản 15 , được phát hành vào ngày 2 tháng 6 năm 2013 .

1
@VikasBansal Dành cho các trình duyệt cũ không hỗ trợ async - cụ thể là IE cũ hơn.
Chris Moschini

13

deferchỉ có thể được sử dụng trong <script>thẻ để bao gồm tập lệnh bên ngoài . Do đó, nó được khuyên nên được sử dụng trong phần <script>-tags trong phần <head>.


8

Vì thuộc tính defer chỉ hoạt động với thẻ scripts với src. Tìm thấy một cách để bắt chước defer cho các tập lệnh nội tuyến. Sử dụng sự kiện DOMContentLoaded.

<script defer src="external-script.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
    // Your inline scripts which uses methods from external-scripts.
});
</script>

Điều này là do, sự kiện DOMContentLoaded kích hoạt sau khi các tập lệnh được quy kết trì hoãn được tải hoàn toàn.


6

Thuộc tính defer chỉ dành cho các tập lệnh bên ngoài (chỉ nên được sử dụng nếu có thuộc tính src).



4

Hãy xem bài viết xuất sắc này Đi sâu vào vùng nước âm u của tải kịch bản do nhà phát triển Google Jake Archibald viết vào năm 2013.

Trích dẫn phần có liên quan từ bài viết đó:

Hoãn lại

<script src="//other-domain.com/1.js" defer></script>
<script src="2.js" defer></script>

Spec nói : Tải xuống cùng nhau, thực hiện theo thứ tự ngay trước khi DOMContentLoaded. Bỏ qua phần mềm trì hoãn trên các tập lệnh mà không có src Cảnh.

IE <10 nói : Tôi có thể thực thi 2.js giữa chừng khi thực hiện 1.js. Không vui sao ??

Các trình duyệt màu đỏ cho biết : Tôi không có ý tưởng gì về việc trì hoãn điều này là gì, tôi sẽ tải các tập lệnh như thể nó không có ở đó.

Các trình duyệt khác nói : Ok, nhưng tôi có thể không bỏ qua các chương trình deferer trên các tập lệnh mà không có src.

(Tôi sẽ thêm các phiên bản đầu tiên của trình kích hoạt Firefox DOMContentLoaded trước khi defertập lệnh kết thúc chạy, theo nhận xét này .)

Các trình duyệt hiện đại dường như hỗ trợ asyncđúng cách, nhưng bạn cần ổn với các tập lệnh sắp hết và có thể trước khi DOMContentLoaded.


1

Thuộc tính Boolean này được đặt để chỉ ra cho trình duyệt rằng tập lệnh có nghĩa là được thực thi sau khi tài liệu được phân tích cú pháp. Vì tính năng này chưa được triển khai bởi tất cả các trình duyệt chính khác, nên các tác giả không nên cho rằng việc thực thi tập lệnh sẽ thực sự bị hoãn lại. Không bao giờ gọi document.write () từ tập lệnh trì hoãn (kể từ Gecko 1.9.2, điều này sẽ thổi bay tài liệu). Thuộc tính defer không nên được sử dụng trên các tập lệnh không có thuộc tính src. Kể từ Gecko 1.9.2, thuộc tính defer bị bỏ qua trên các tập lệnh không có thuộc tính src. Tuy nhiên, trong Gecko 1.9.1, ngay cả các tập lệnh nội tuyến cũng được hoãn lại nếu thuộc tính defer được đặt.

defer hoạt động với chrome, firefox, tức là> 7 và Safari

ref: https://developer.mozilla.org/en-US/docs/HTML/Euity/script


0

Thuộc tính defer là thuộc tính boolean.

Khi có mặt, nó chỉ định rằng tập lệnh được thực thi khi trang đã phân tích xong.

Lưu ý: Thuộc tính defer chỉ dành cho các tập lệnh bên ngoài (chỉ nên được sử dụng nếu có thuộc tính src).

Lưu ý: Có một số cách mà tập lệnh bên ngoài có thể được thực thi:

Nếu có async: Tập lệnh được thực thi không đồng bộ với phần còn lại của trang (tập lệnh sẽ được thực thi trong khi trang tiếp tục phân tích cú pháp) Nếu không có async và hiện diện defer: Tập lệnh được thực thi khi trang đã phân tích xong không có async hoặc defer hiện diện: Tập lệnh được tìm nạp và thực thi ngay lập tức, trước khi trình duyệt tiếp tục phân tích trang

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.