为什么document.write被视为“不良做法”?


363

我知道这document.write被认为是不良做法;并且,我希望整理出一个原因清单,以便向第三方供应商提交有关为什么不应该document.write在其分析代码的实现中使用它们的原因。

document.write在下面列出您声称是不良做法的原因。

Answers:


243

一些较严重的问题:

  • document.write(此后称为DW)在XHTML中不起作用

  • DW不会直接修改DOM,从而阻止了进一步的操作 (试图寻找证据,但充其量只是视情况而定)

  • 页面加载完成后执行的DW将覆盖页面,或写入新页面,或不起作用

  • DW在遇到的地方执行:它无法在给定的节点上注入

  • DW有效地编写了序列化的文本,这不是DOM在概念上的工作方式,并且是创建错误的简便方法(.innerHTML存在相同的问题)

使用安全且对DOM友好的DOM操作方法要好得多


39
-1,它绝对修改DOM。其他一切都很好。虽然我了解必须依靠可以防止伤害的结构和方法的冲动,但这种情况可能是将婴儿与沐浴水一起扔掉的情况。
cgp

7
FireBug不是DOM的真实表示。Mozilla尝试将HTML解析为DOM。您可以在Firebug DOM视图中完全破坏HTML外观。
FlySwat

8
DOM是用于呈现页面的数据结构,因此是用户在页面上看到的内容的Alpha和Omega。您是正确的HTML!= DOM,但这对于DW是否修改DOM的问题无关紧要。如果DW没有修改DOM,那么您将看不到屏幕-所有浏览器都是如此,并且只要DOM是用于呈现页面的对象,屏幕就一直存在。
cgp

8
“ DW在遇到的地方执行” -并非总是不利的,实际上对于某些事情来说,它可以被认为是一个优点,例如,添加脚本元素(实际上是我要使用DW的唯一事情,即使那样我也会三思而后行) 。
nnnnnn

7
@RicardoRivaldo是的,如果document.write文档加载完成后被调用,它们会这样做
Izkata 2013年

124

document.write本质上,实际上没有任何问题。问题在于滥用它真的很容易。总的来说,甚至。

对于供应商提供分析代码(例如Google Analytics(分析))而言,这实际上是他们分发此类代码段的最简单方法

  1. 它使脚本较小
  2. 他们不必担心会覆盖已经建立的onload事件或包括必要的抽象以安全地添加onload事件
  3. 极其兼容

根据document.write我的拙见,只要您在文档加载后不尝试使用它,并不是天生就是邪恶的。


3
document.write确实会对html解析器造成可怕的影响,并且仅在简单情况下“完全兼容”。
olliej

27
像插入分析标签一样?毕竟,这就是原始问题的一部分。通过高度兼容,我的意思是仅对document.write方法提供原始浏览器支持。
彼得·贝利

任何与最新版本的Chrome / IE / Safari / Opera / FireFox兼容的产品均被视为兼容。
Pacerier 2014年

2
覆盖onload事件?那是addEventListener为了什么?
m93a 2015年

document.write当满足某些条件时,Chrome将不会运行插入脚本的调用。
Flimm

44

的另一合法用途document.write来自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>

我也看到了使用json2.js JSON解析/字符串化polyfill的相同技术(IE7及以下版本需要)。

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

11
此处使用情况不错,但仍然“更好”地使用DOM操作功能-甚至Google也在Google Analytics(分析)中使用它。片段在这里
BMiner 2013年

8
@BMiner如果script通过DOM操作插入元素,是否同步加载?除非是,否则它不是替代品。
John Dvorak 2013年

2
@JanDvorak-好点;使用DOM操作时,浏览器通常会异步加载脚本。您可以使用onloadDOM事件来确定何时可以使用异步加载的脚本。
BMiner 2013年

1
@JanDvorak 如果不是外部的(没有src),则它是同步加载的。否则,它将“尽快”异步执行。
Oriol

1
这仍然可能会中断,因为Chrome会故意拒绝运行document.write插入的呼叫<script>如果用户使用2G连接标签的。见developers.google.com/web/updates/2016/08/...
Flimm

42

它可以阻止您的页面

document.write仅在页面加载时有效;如果在页面加载完成后调用它,它将覆盖整个页面。

这实际上意味着您必须从嵌入式脚本块中调用它-并且这将阻止浏览器处理随后的页面部分。在编写块完成之前,不会下载脚本和图像。


31

优点:

  • 这是从外部(到主机/域)脚本中嵌入内联内容的最简单方法。
  • 您可以覆盖框架/ iframe中的全部内容。在更现代的Ajax技术广泛使用之前(1998年至2002年),我曾经在菜单/导航部分中经常使用此技术。

缺点:

  • 它序列化渲染引擎以暂停,直到加载所述外部脚本为止,这可能比内部脚本花费更长的时间。
  • 通常以将脚本放置在内容中的方式使用,这被认为是错误的形式。

3
缺点更多。例如,在某些情况下,谷歌浏览器将拒绝运行document.write创建<script>标记的代码。developers.google.com/web/updates/2016/08/…–
Flimm

@Flimm值得注意的是,您的评论距我的回答已经超过8年,而这将近3年。是的,还有其他弊端……如果document.write本身没有消失……以及其他一些滥用严重的接口,我会感到惊讶。
Tracker1

10

这是我的两便士,一般来说,您不应该将其document.write用于繁重的工作,但是在某些情况下,它绝对有用:

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

我最近发现这个尝试创建AJAX滑块库。我创建了两个嵌套的div,然后将width/ height和应用overflow: hidden到外部<div>使用JS。这样一来,如果浏览器禁用了JS,则div会浮动以容纳图库中的图像-一些不错的优雅降级。

就像上面的文章一样,这种CSS的JS劫持直到页面加载完成后才开始,导致div加载时出现瞬时闪烁。因此,我需要在加载页面时编写CSS规则或包含一张工作表。

显然,这在XHTML中是行不通的,但是由于XHTML看起来像是死鸡了(并且在IE中显示为标签汤),因此可能值得重新评估您对DOCTYPE的选择...


7

它会覆盖页面上的内容,这是最明显的原因,但是我不会称其为“不好”。

除非使用JavaScript创建整个文档,否则它用处不大,在这种情况下,您可以从document.write开始。

即使这样,当您使用document.write时,您并没有真正利用DOM -您只是将一小段文本转储到文档中,所以我认为这是一种不好的形式。


2
需要澄清的一点是:document.write在页面上插入内容,但不会覆盖它们。
彼得·多尔伯格

5
@Peter,如果您在文档加载后调用内容,它将覆盖内容。我猜这就是aleemb的意思。
马修·

2
您是否建议人们应该在代码中手动构建各个DOM节点,而不是仅仅做类似的事情div.innerHTML = "<label for='MySelect'>Choose One</label><select id='MySelect'><option value='foo' selected=''>foo</option><option value='bar'>bar</option></select>";?这似乎会产生许多不必要的和可读性较低的代码。这也与John Resig和其他JS开发人员所倡导的方法完全相反。
冒犯君主

7

它使用XML渲染破坏页面(例如XHTML页面)。

最好:将一些浏览器切换回HTML渲染,然后一切正常。

可能:某些浏览器在XML呈现模式下禁用document.write()函数。

最糟糕的是:每当使用document.write()函数时,某些浏览器都会触发XML错误。


6

从我的头顶上:

  1. document.write需要在页面加载或正文加载中使用。因此,如果您想在其他时间使用脚本来更新页面内容document.write几乎没有用。

  2. 从技术上讲,document.write只会更新HTML页面,而不会更新XHTML / XML。IE似乎可以宽容这个事实,但其他浏览器却不会。

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


9
IE之所以宽容,是因为它不支持XHTML。如果这样做的话,document.write可能会停止工作(当然,仅在XHTML中)。
马修·克鲁姆利

2
XHTML与Web无关。用严格的XHTML文档类型偶数页实际上并没有在这方面的XML处理,浏览器开发商不信任网页的作者多少。
RobG 2015年


3

违反浏览器

.write被视为违反浏览器,因为它会停止解析器渲染页面。解析器收到消息,该文档正在被修改;因此,它会被阻塞,直到JS完成其过程为止。仅在此时,解析器才能恢复。

性能

采用这种方法的最大结果是性能降低。浏览器将花费更长的时间来加载页面内容。对加载时间的不利反应取决于要写入文档的内容。如果您<p>要向DOM 添加标签,而不是将对JavaScript库的50多个引用传递给数组,则不会有太大的区别(我在工作代码中已经看到这种情况,导致11秒钟的延迟)当然,这也取决于您的硬件)。

总而言之,如果可以帮助,最好避免使用此方法。

有关更多信息,请参见干预document.write()



2
  • document.write不良做法的一个简单原因是,您无法提出无法找到更好替代方案的方案。
  • 另一个原因是您正在处理字符串而不是对象(这是非常原始的)。
  • 它仅附加到文档。
  • 它没有MVC(模型-视图-控制器)模式的任何优点。
  • 使用ajax + jQueryangularJS呈现动态内容的功能要强大得多

至于您的第一个项目符号,您将如何解决@sunwukung在上面他的回答中描述的内容?我同意您可以使用DOM操纵解决它,但是随着DOM操纵的发展,有时有时很难避免FUOC document.write
伯特·布鲁伊诺赫(Robert Bruynooghe)'17

FUOC不再是问题了吗?
安德斯·林登18'Aug

1

可以将document.write()(和.innerHTML)视为评估源代码字符串。对于许多应用程序来说,这可能非常方便。例如,如果您从某个来源获得HTML代码作为字符串,则只需“评估”它就很方便。

在Lisp的上下文中,DOM操作就像操作列表结构,例如,通过执行以下操作创建列表(橙色):

(cons 'orange '())

而document.write()就像评估字符串一样,例如,通过评估如下的源代码字符串来创建列表:

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

Lisp还具有使用列表操作创建代码的非常有用的功能(例如使用“ DOM样式”创建JS解析树)。这意味着您可以使用“ DOM样式”而不是“字符串样式”建立列表结构,然后运行该代码,例如:

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

如果您实现像简单的实时编辑器这样的编码工具,则具有快速评估字符串的能力非常方便,例如使用document.write()或.innerHTML。从这个意义上讲,Lisp是理想的选择,但是您也可以在JS中完成非常酷的工作,而且很多人都在这样做,例如http://jsbin.com/


1

document.write的缺点主要取决于以下三个因素:

a)实施

document.write()通常用于在需要内容时将内容写入屏幕。这意味着它发生在任何地方,无论是在JavaScript文件中还是在HTML文件中的脚本标签内。将script标记放置在此类HTML文件中的任何位置,在文档块中将document.write()语句与网页中的HTML交织在一起是一个不好的主意。

b)渲染

通常,设计良好的代码将采用任何动态生成的内容,将其存储在内存中,并在其最终通过屏幕显示出来之前继续对其进行操作。因此,要重申上一节中的最后一点,就地渲染内容可能比可能依赖的其他内容渲染速度更快,但是其他代码可能无法使用它反过来又需要渲染内容进行处理。为了解决这个难题,我们需要摆脱document.write()并以正确的方式实现它。

c)不可能的操纵

一旦写完,就结束了。如果不使用DOM,我们将无法回过头来对其进行操作。


1

我认为使用document.write根本不是一个坏习惯。简单来说,这对没有经验的人来说就像是高压。如果使用错误的方法,则会煮熟。有许多开发人员至少使用过一次此方法和其他危险方法,他们从未真正挖掘过自己的失败。相反,当出现问题时,他们会纾困,并使用更安全的东西。这些人就所谓的“不良做法”发表此类声明。

这就像格式化硬盘驱动器一样,当您只需要删除几个文件然后说“格式化驱动器是一个坏习惯”时。


-3

我认为最大的问题是,通过document.write编写的任何元素都被添加到页面元素的末尾。对于现代页面布局和AJAX来说,这很少达到预期的效果。(您必须记住,DOM中的元素是临时的,脚本运行时可能会影响其行为)。

最好在页面上设置一个占位符元素,然后操纵它的innerHTML。


15
这不是真的。document.write不会像添加内容一样将内容添加到页面的末尾。它们写在适当的位置。
彼得·贝利

1
@Peter Bailey,我知道这是一个老话题,但实际上不应对此予以拒绝。是否追加取决于页面加载时document.write()是否以内联方式运行。如果在页面加载后从函数中调用它,则第一个document.write()将替换整个正文,随后的调用将追加到它上面。
章鱼

3
@Octopus是的,但这是偶然的。它之所以会追加是因为存在一个新文档。说“ document.write()追加”仍然不准确。是的,这是一个古老的答案,而且是一个过时的选票,但我仍然坚持。
彼得·贝利

没关系。我讲得不准确。我早就已经编辑过,但是上面有一个更好的答案。我要指出的是,“就地编写”同样不精确。
BnWasteland 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.