Tại sao document.write được coi là một hành vi xấu của người Viking?


363

Tôi biết document.writeđược coi là thực hành xấu; và tôi hy vọng sẽ tổng hợp danh sách các lý do để gửi cho nhà cung cấp bên thứ 3 về lý do tại sao họ không nên sử dụng document.writeđể triển khai mã phân tích của mình.

Vui lòng bao gồm lý do của bạn để tuyên bố document.writelà một thực hành xấu dưới đây.

Câu trả lời:


243

Một số vấn đề nghiêm trọng hơn:

  • document.write (từ đó DW) không hoạt động trong XHTML

  • DW không trực tiếp sửa đổi DOM, ngăn chặn thao túng thêm (cố gắng tìm bằng chứng về điều này, nhưng đó là tình huống tốt nhất)

  • DW thực hiện sau khi tải xong trang sẽ ghi đè lên trang hoặc viết một trang mới hoặc không hoạt động

  • DW thực thi ở nơi gặp phải: nó không thể tiêm tại một điểm nút nhất định

  • DW đang viết văn bản tuần tự một cách hiệu quả, đó không phải là cách DOM hoạt động theo khái niệm và là một cách dễ dàng để tạo ra lỗi (.innerHTML có cùng một vấn đề)

Tốt hơn nhiều để sử dụng các phương thức thao tác DOM thân thiện và an toàn với DOM


39
-1, nó hoàn toàn sửa đổi DOM. Mọi thứ khác đều ổn. Mặc dù tôi hiểu sự thôi thúc phụ thuộc vào cấu trúc và phương pháp có thể giúp bạn không bị tổn hại, đây có thể là một trường hợp vứt bỏ em bé bằng nước tắm.
cgp

7
FireBug không phải là một đại diện thực sự của DOM. Đây là nỗ lực của mozilla để phân tích HTML thành một DOM. Bạn có thể đã hoàn toàn phá vỡ HTML trông phù hợp trong chế độ xem Firebird DOM.
FlySwat

8
DOM là cấu trúc dữ liệu được sử dụng để hiển thị trang và như vậy là alpha và omega của những gì người dùng nhìn thấy trên trang. Bạn đã đúng rằng HTML! = DOM, nhưng nó không quan trọng đối với câu hỏi liệu DOM có được sửa đổi bởi DW hay không. Nếu DW không sửa đổi DOM, bạn sẽ không nhìn thấy màn hình - điều đó đúng với tất cả các trình duyệt và sẽ luôn miễn là DOM là thứ được sử dụng để hiển thị trang.
cgp

8
"DW thực thi ở nơi gặp phải" - không phải lúc nào cũng là nhược điểm, thực sự nó có thể được coi là một lợi thế cho một số thứ nhất định, ví dụ: thêm các yếu tố tập lệnh (thực sự là về điều duy nhất tôi sử dụng DW, và thậm chí sau đó tôi sẽ nghĩ hai lần) .
nnnnnn

7
@RicardoRivaldo Có, họ sẽ làm, nếu document.writeđược gọi sau khi tài liệu đã tải xong
Izkata

124

Thực sự không có gì sai với document.write, mỗi người. Vấn đề là nó rất dễ sử dụng sai. Tổng thể, thậm chí.

Đối với các nhà cung cấp cung cấp mã phân tích (như Google Analytics), đây thực sự là cách dễ nhất để họ phân phối các đoạn như vậy

  1. Nó giữ cho các kịch bản nhỏ
  2. Họ không phải lo lắng về việc ghi đè các sự kiện onload đã được thiết lập hoặc bao gồm cả sự trừu tượng cần thiết để thêm các sự kiện onload một cách an toàn
  3. Nó cực kỳ tương thích

Miễn là bạn không thử sử dụng nó sau khi tài liệu đã được tải ,document.writetheo ý kiến ​​khiêm tốn của tôi.


3
document.write thực hiện những điều thực sự khủng khiếp đối với các trình phân tích cú pháp html và chỉ "cực kỳ tương thích" trong các trường hợp đơn giản.
olliej

27
Giống như việc chèn thẻ phân tích? Rốt cuộc, đó là một phần của câu hỏi ban đầu. Và bởi cực kỳ tương thích, ý tôi là chỉ hỗ trợ trình duyệt thô cho phương thức document.write.
Peter Bailey

Bất cứ điều gì hoạt động với các phiên bản Chrome / IE / Safari / Opera / FireFox mới nhất đều được coi là tương thích.
Pacerier

2
Ghi đè các sự kiện onload? Và addEventListenerđể làm gì?
m93a

Chrome sẽ không chạy các document.writeyêu cầu chèn tập lệnh khi đáp ứng một số điều kiện nhất định.
Flimm

44

Một cách sử dụng hợp pháp khác document.writeđến từ ví dụ HTML5 Boilerplate index.html .

<!-- Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if offline -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.6.3.min.js"><\/script>')</script>

Tôi cũng thấy các kỹ thuật tương tự để sử dụng json2.js JSON phân tích cú pháp / stringify polyfill ( cần thiết cho IE7 và dưới ).

<script>window.JSON || document.write('<script src="json2.js"><\/script>')</script>

11
Sử dụng không tệ ở đây, nhưng vẫn "tốt hơn" để sử dụng các chức năng thao tác DOM - ngay cả Google cũng làm điều đó cho Google Analytics. Đoạn trích ở đây .
BMiner

8
@BMiner nếu bạn chèn một scriptphần tử thông qua thao tác DOM, nó có được tải đồng bộ không? Trừ khi nó là, nó không phải là một thay thế.
John Dvorak

2
@JanDvorak - Điểm tốt; khi sử dụng các thao tác DOM, các trình duyệt thường sẽ tải tập lệnh không đồng bộ. Bạn có thể sử dụng onloadsự kiện DOM để xác định khi nào tập lệnh được tải không đồng bộ có sẵn để sử dụng.
BMiner

1
@JanDvorak Nó được tải đồng bộ nếu không phải là bên ngoài (không có src) . Nếu không, nó sẽ được thực thi "càng sớm càng tốt", không đồng bộ.
Oriol

1
Điều này vẫn có thể phá vỡ, vì Chrome sẽ cố tình từ chối thực hiện document.writecác cuộc gọi chèn <script>thẻ nếu người dùng đang sử dụng kết nối 2G. Xem nhà phát
triển.google.com/web/updates/2016/08/ trên

42

Nó có thể chặn trang của bạn

document.writechỉ hoạt động trong khi trang đang tải; Nếu bạn gọi nó sau khi tải xong trang, nó sẽ ghi đè lên toàn bộ trang.

Điều này có nghĩa là bạn phải gọi nó từ một khối tập lệnh nội tuyến - Và điều đó sẽ ngăn trình duyệt xử lý các phần của trang tiếp theo. Tập lệnh và hình ảnh sẽ không được tải xuống cho đến khi khối viết kết thúc.


31

Chuyên nghiệp:

  • Đó là cách dễ nhất để nhúng nội dung nội tuyến từ tập lệnh bên ngoài (vào máy chủ / tên miền) của bạn.
  • Bạn có thể ghi đè lên toàn bộ nội dung trong khung / iframe. Tôi đã từng sử dụng kỹ thuật này rất nhiều cho các phần menu / điều hướng trước khi các kỹ thuật Ajax hiện đại hơn được phổ biến rộng rãi (1998-2002).

Con:

  • Nó tuần tự hóa công cụ kết xuất để tạm dừng cho đến khi tập lệnh bên ngoài được tải, có thể mất nhiều thời gian hơn tập lệnh bên trong.
  • Nó thường được sử dụng theo cách mà tập lệnh được đặt trong nội dung, được coi là hình thức xấu.

3
Có nhiều khuyết điểm hơn thế. Chẳng hạn, Google Chrome sẽ từ chối chạy thẻ document.writetạo <script>trong các trường hợp nhất định. developers.google.com/web/updates/2016/08/ trên
Flimm

@Flimm thật đáng chú ý, nhận xét của bạn là hơn 8 năm sau câu trả lời của tôi và điều này gần 3 năm sau. Vâng, có những khuyết điểm khác ... và tôi sẽ ngạc nhiên nếu document.write không biến mất ... cũng như có thể một số giao diện bị lạm dụng cao khác.
Tracker1

10

Đây là giá trị gấp đôi của tôi, nói chung bạn không nên sử dụng document.writecho việc nâng vật nặng, nhưng có một trường hợp chắc chắn là hữu ích:

http://www.quirksmode.org/blog/archives/2005/06/three_javascrip_1.html

Tôi phát hiện ra điều này gần đây khi cố gắng tạo một bộ sưu tập thanh trượt AJAX. Tôi đã tạo hai div lồng nhau và áp dụng width/ heightoverflow: hiddenbên ngoài <div>với JS. Điều này là do trong trường hợp trình duyệt đã tắt JS, div sẽ nổi để chứa các hình ảnh trong bộ sưu tập - một số suy giảm duyên dáng tốt đẹp.

Điều quan trọng là, như với bài viết ở trên, việc chiếm quyền điều khiển CSS này đã không khởi động cho đến khi trang được tải, gây ra một chớp nhoáng khi div được tải. Vì vậy, tôi cần phải viết một quy tắc CSS, hoặc bao gồm một trang tính, khi trang được tải.

Rõ ràng, điều này sẽ không hoạt động trong XHTML, nhưng vì XHTML dường như là một con vịt chết (và được gọi là súp thẻ trong IE) nên có thể đánh giá lại sự lựa chọn của bạn về DOCTYPE ...


7

Nó ghi đè lên nội dung trên trang đó là lý do rõ ràng nhất nhưng tôi sẽ không gọi nó là "xấu".

Nó chỉ không được sử dụng nhiều trừ khi bạn tạo toàn bộ tài liệu bằng JavaScript trong trường hợp bạn có thể bắt đầu với document.write.

Mặc dù vậy, bạn không thực sự tận dụng DOM khi bạn sử dụng document.write - bạn chỉ bỏ một đốm văn bản vào tài liệu nên tôi nói đó là hình thức xấu.


2
Một cách làm rõ: document.write chèn nội dung trên trang, nó không ghi đè lên chúng.
Peter Dolberg

5
@Peter, nó sẽ ghi đè lên nội dung nếu bạn gọi nó sau khi tài liệu được tải. Tôi đoán đó là ý nghĩa của aleemb.
Matthew Crumley

2
Thay vào đó, bạn có gợi ý rằng người ta nên xây dựng các nút DOM riêng lẻ trong mã thay vì chỉ làm một cái gì đó như thế div.innerHTML = "<label for='MySelect'>Choose One</label><select id='MySelect'><option value='foo' selected=''>foo</option><option value='bar'>bar</option></select>";nào không? Có vẻ như nó sẽ tạo ra rất nhiều mã không cần thiết và ít đọc hơn. Nó cũng hoàn toàn trái ngược với cách tiếp cận John Resig và những người ủng hộ các nhà phát triển JS khác.
Lèse hùng vĩ

7

Nó phá vỡ các trang bằng cách sử dụng kết xuất XML (như các trang XHTML).

Tốt nhất : một số trình duyệt chuyển trở lại kết xuất HTML và mọi thứ đều hoạt động tốt.

Có thể : một số trình duyệt vô hiệu hóa hàm document.write () trong chế độ kết xuất XML.

Tệ nhất : một số trình duyệt sẽ phát sinh lỗi XML bất cứ khi nào sử dụng hàm document.write ().


6

Off đỉnh đầu của tôi:

  1. document.writecần được sử dụng trong tải trang hoặc tải cơ thể. Vì vậy, nếu bạn muốn sử dụng tập lệnh vào bất kỳ thời điểm nào khác để cập nhật nội dung trang của bạn thì document.write khá vô dụng.

  2. Về mặt kỹ thuật document.writesẽ chỉ cập nhật các trang HTML chứ không phải XHTML / XML. IE dường như khá tha thứ cho thực tế này nhưng các trình duyệt khác thì không.

http://www.w3.org/MarkUp/2004/xhtml-faq#docwrite


9
IE đang tha thứ vì nó không hỗ trợ XHTML. Nếu / khi họ làm, document.write có thể sẽ ngừng hoạt động (tất nhiên chỉ có trong XHTML).
Matthew Crumley

2
XHTML không liên quan trên web. Trang ngay cả với một DOCTYPE XHTML nghiêm ngặt không thực sự coi là XML trong vấn đề đó, các nhà phát triển trình duyệt không giả trang tin tưởng rằng nhiều.
RobG

4

Chrome có thể chặn document.writeviệc chèn tập lệnh trong một số trường hợp nhất định. Khi điều này xảy ra, nó sẽ hiển thị cảnh báo này trong bảng điều khiển:

Một tập lệnh phân tích cú pháp, mã nguồn gốc chéo, ..., được gọi thông qua document.write. Điều này có thể bị chặn bởi trình duyệt nếu thiết bị có kết nối mạng kém.

Người giới thiệu:


3

Vi phạm trình duyệt

.writeđược coi là vi phạm trình duyệt vì nó tạm dừng trình phân tích cú pháp hiển thị trang. Trình phân tích cú pháp nhận được thông báo rằng tài liệu đang được sửa đổi; do đó, nó bị chặn cho đến khi JS hoàn thành quy trình của nó. Chỉ tại thời điểm này, trình phân tích cú pháp sẽ tiếp tục.

Hiệu suất

Hậu quả lớn nhất của việc sử dụng một phương pháp như vậy là hiệu suất thấp hơn. Trình duyệt sẽ mất nhiều thời gian hơn để tải nội dung trang. Phản ứng bất lợi về thời gian tải phụ thuộc vào những gì được ghi vào tài liệu. Bạn sẽ không thấy nhiều sự khác biệt nếu bạn thêm<p> thẻ vào DOM trái ngược với việc chuyển một mảng 50-một số tham chiếu đến các thư viện JavaScript (điều mà tôi đã thấy trong mã làm việc và dẫn đến độ trễ 11 giây - của Tất nhiên, điều này cũng phụ thuộc vào phần cứng của bạn).

Nói chung, tốt nhất là tránh xa phương pháp này nếu bạn có thể giúp đỡ.

Để biết thêm thông tin, xem Can thiệp vào document.write ()


3

Dựa trên phân tích được thực hiện bởi Kiểm toán ngọn hải đăng của Google-Chrome Dev Tools ,

Đối với người dùng trên các kết nối chậm, các tập lệnh bên ngoài được chèn động qua document.write()có thể trì hoãn tải trang hàng chục giây.

nhập mô tả hình ảnh ở đây


2
  • Một lý do đơn giản tại sao document.writemột thực tiễn xấu là bạn không thể đưa ra một kịch bản mà bạn không thể tìm thấy một sự thay thế tốt hơn.
  • Một lý do khác là bạn đang xử lý các chuỗi thay vì các đối tượng (nó rất nguyên thủy).
  • Nó chỉ nối vào tài liệu.
  • Nó không có gì đẹp bằng ví dụ mẫu MVC (Model-View-Controller) .
  • Việc trình bày nội dung động với ajax + jQuery hoặc angularJS sẽ mạnh mẽ hơn rất nhiều .

Đối với viên đạn đầu tiên của bạn, bạn sẽ giải quyết những gì @sunwukung mô tả trong câu trả lời của anh ấy ở trên? Tôi đồng ý rằng bạn có thể giải quyết nó bằng các thao tác DOM, nhưng khi các thao tác DOM đi, thật khó để tránh FUOC vào những lúc không có document.write.
bert bruynooghe

FUOC có phải là vấn đề nữa không?
Anders Lindén

1

Người ta có thể nghĩ về document.write () (và .innerHTML) khi đánh giá chuỗi mã nguồn. Điều này có thể rất tiện dụng cho nhiều ứng dụng. Ví dụ: nếu bạn lấy mã HTML dưới dạng một chuỗi từ một số nguồn, sẽ rất hữu ích khi chỉ "đánh giá" nó.

Trong ngữ cảnh của Lisp, thao tác DOM sẽ giống như thao tác cấu trúc danh sách, ví dụ: tạo danh sách (màu cam) bằng cách thực hiện:

(cons 'orange '())

Và document.write () sẽ giống như đánh giá một chuỗi, ví dụ: tạo danh sách bằng cách đánh giá chuỗi mã nguồn như thế này:

(eval-string "(cons 'orange '())")

Lisp cũng có khả năng rất hữu ích để tạo mã bằng cách sử dụng thao tác danh sách (như sử dụng "kiểu DOM" để tạo cây phân tích cú pháp JS). Điều này có nghĩa là bạn có thể xây dựng cấu trúc danh sách bằng cách sử dụng "kiểu DOM", thay vì "kiểu chuỗi", rồi chạy mã đó, ví dụ như thế này:

(eval '(cons 'orange '()))

Nếu bạn triển khai các công cụ mã hóa, như các trình soạn thảo trực tiếp đơn giản, sẽ rất thuận tiện để có khả năng đánh giá nhanh một chuỗi, ví dụ như sử dụng document.write () hoặc .innerHTML. Lisp là lý tưởng theo nghĩa này, nhưng bạn cũng có thể làm những thứ rất tuyệt vời trong JS và nhiều người đang làm điều đó, như http://jsbin.com/


1

Những nhược điểm của document.write chủ yếu phụ thuộc vào 3 yếu tố sau:

a) Thực hiện

Document.write () chủ yếu được sử dụng để ghi nội dung lên màn hình ngay khi nội dung đó là cần thiết. Điều này có nghĩa là nó xảy ra ở bất kỳ đâu, trong tệp JavaScript hoặc bên trong thẻ script trong tệp HTML. Với thẻ script được đặt ở bất kỳ đâu trong tệp HTML như vậy, một ý tưởng tồi là có các câu lệnh document.write () bên trong các khối tập lệnh được đan xen với HTML bên trong một trang web.

b) Kết xuất

Mã được thiết kế tốt nói chung sẽ lấy bất kỳ nội dung được tạo động nào, lưu trữ nó trong bộ nhớ, tiếp tục thao tác với nó khi nó đi qua mã trước khi cuối cùng nó được đưa ra màn hình. Vì vậy, để nhắc lại điểm cuối cùng trong phần trước, kết xuất nội dung tại chỗ có thể hiển thị nhanh hơn nội dung khác có thể dựa vào, nhưng nó có thể không có sẵn cho mã khác mà lần lượt yêu cầu phải hiển thị nội dung để xử lý. Để giải quyết vấn đề nan giải này, chúng ta cần loại bỏ document.write () và thực hiện nó đúng cách.

c) Thao tác bất khả thi

Một khi nó được viết xong và kết thúc. Chúng tôi không thể quay lại để thao tác nó mà không cần nhấn vào DOM.


1

Tôi không nghĩ sử dụng document.write là một cách thực hành tồi. Nói một cách đơn giản, nó giống như một điện áp cao cho những người thiếu kinh nghiệm. Nếu bạn sử dụng sai cách, bạn sẽ bị chín. Có nhiều nhà phát triển đã sử dụng phương pháp này và các phương pháp nguy hiểm khác ít nhất một lần và họ không bao giờ thực sự đào sâu vào thất bại của mình. Thay vào đó, khi có sự cố xảy ra, họ chỉ bảo lãnh và sử dụng thứ gì đó an toàn hơn. Đó là những người đưa ra những tuyên bố như vậy về những gì được coi là "Thực hành xấu".

Nó giống như định dạng ổ đĩa cứng, khi bạn chỉ cần xóa một vài tệp và sau đó nói "định dạng ổ đĩa là một thực tiễn xấu".


-3

Tôi nghĩ vấn đề lớn nhất là bất kỳ yếu tố nào được viết qua document.write đều được thêm vào cuối các yếu tố của trang. Đó hiếm khi là hiệu ứng mong muốn với bố cục trang hiện đại và AJAX. (bạn phải nhớ rằng các thành phần trong DOM là tạm thời và khi tập lệnh chạy có thể ảnh hưởng đến hành vi của nó).

Sẽ tốt hơn nhiều nếu đặt phần tử giữ chỗ trên trang và sau đó thao tác bên trongHTML.


15
Đây không phải là sự thật. document.write không thêm nội dung vào cuối trang như nó là phần phụ. Chúng được viết tại chỗ.
Peter Bailey

1
@Peter Bailey, tôi biết đây là một chủ đề cũ, nhưng thực sự điều này không nên bị hạ thấp. nó có nối thêm hay không phụ thuộc vào việc document.write () có chạy nội tuyến trong khi trang đang tải hay không. Nếu nó được gọi từ một hàm sau khi tải trang thì document.write () đầu tiên sẽ thay thế toàn bộ phần thân và các cuộc gọi tiếp theo sẽ nối vào nó.
Bạch tuộc

3
@Octopus Có, nhưng đó là hoàn cảnh. Nó chỉ xuất hiện trong kịch bản đó bởi vì có một tài liệu mới. Vẫn chưa chính xác khi nói "document.write () nối thêm." Vâng, đó là một câu trả lời cũ và một downvote cũ, nhưng tôi vẫn đứng bên cạnh nó.
Peter Bailey

Tốt rồi. Tôi nói không chính xác. Tôi đã chỉnh sửa nó từ lâu, nhưng có một câu trả lời tốt hơn nhiều ở trên. Tôi sẽ chỉ ra rằng "viết tại chỗ" là không chính xác như nhau.
BnWasteland
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.