为什么说document.write被认为是“不良实践”?

394

我知道 document.write 被认为是不良实践;我希望列举出一些理由,提交给第三方供应商,告诉他们为什么不能在分析代码的实现中使用 document.write

请在下面提供您认为 document.write 是不良实践的原因。

17个回答

262

一些比较严重的问题:

  • document.write (以下简称DW) 在XHTML中无法使用

  • DW无法直接修改DOM,防止进一步操作(正在尝试找到证据,但这最多是情景问题)

  • 在页面加载完成后执行DW会覆盖页面、编写新页面或不起作用

  • DW在遇到时就执行:它无法注入到特定节点点

  • DW实际上是在写序列化文本,这不是DOM在概念上工作的方式,也是创建错误的简单方法(.innerHTML也有同样的问题)

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


45
-1,它绝对会修改DOM。其他一切都没问题。尽管我理解依赖可以使你免于受伤的结构和方法的冲动,但这可能是把孩子和洗澡水一起扔掉的情况。 - cgp
7
Firebug不是DOM的真实表示。它是Mozilla尝试将HTML解析成DOM的工具。在Firebug的DOM视图中,即使HTML代码存在错误,也可能会显示为正确的形式。 - FlySwat
9
DOM 是用于渲染页面的数据结构,因此是用户在页面上看到的一切的起点和终点。你说得没错,HTML 不等同于 DOM,但这与 DW 是否修改了 DOM 无关。如果 DW 没有修改 DOM,那么你就看不到屏幕——所有浏览器都是如此,只要 DOM 用于渲染页面,永远都会是这样。请注意,我已经尽力使翻译更加通俗易懂,但没有改变原来的意思。 - cgp
9
“DW executes where encountered”并不总是一个劣势,事实上,在某些情况下可以被视为优势,例如添加脚本元素(这实际上是我使用DW的唯一事情,即使如此,我也会三思而后行)。 - nnnnnn
8
好的,我会尽力进行翻译。如果在文档完成加载后调用了document.write,那么它们就会起作用。 - Izkata
显示剩余13条评论

134

document.write 本身实际上没有任何问题,问题在于使用起来非常容易出错,甚至是严重的错误。

对于提供分析代码(例如Google Analytics)的供应商来说,这实际上是他们分发这些代码片段的最简单方法:

  1. 脚本保持简短
  2. 他们不必担心覆盖已经建立的onload事件或包含必要的抽象以安全地添加onload事件
  3. 它非常兼容

只要不在文档加载完成后尝试使用它,在我看来,document.write 并不是本质上邪恶的东西。


5
document.write 对 HTML 解析器造成了非常糟糕的影响,只有在简单情况下才是“极其兼容”的。 - olliej
28
像插入分析标签一样吗?毕竟,这是原始问题的一部分。 所谓“极度兼容”,指的是对于document.write方法的原始浏览器支持。 - Peter Bailey
任何与最新版本的Chrome / IE / Safari / Opera / FireFox兼容的内容都被认为是兼容的。 - Pacerier
2
覆盖 onload 事件?addEventListener 是用来做什么的? - m93a
当满足某些条件时,Chrome将不会运行插入脚本的document.write调用。 - Flimm
@Flimm和读者们:使用document.write插入与HTML页面相同域的脚本标签应该是安全的 - traktor

45

它可以阻止您的页面

document.write 只能在页面加载时起作用;如果在页面加载完成后调用它,它将覆盖整个页面。

这实际上意味着您必须从内联脚本块中调用它,而这将阻止浏览器处理随后的页面部分。直到写入块完成之前,脚本和图像都不会被下载。


45

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解析/字符串填充(IE7及以下版本需要)。

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

12
这里用得不错,但仍然更好使用DOM操作函数——即使是谷歌在使用Google Analytics时也是如此。代码片段在这里 - BMiner
9
如果通过DOM操作插入script元素,它是否同步加载?除非是这样,否则它不是一个替代品。 - John Dvorak
2
@JanDvorak - 很好的观点;当使用DOM操作时,浏览器通常会异步加载脚本。您可以使用onload DOM事件来确定异步加载的脚本何时可用于使用。 - BMiner
1
如果它不是外部的(没有src),则会同步加载。否则,它将异步地“尽快”执行。 - Oriol
1
这仍然可能会出现问题,因为如果用户处于2G连接状态,Chrome将故意拒绝运行插入<script>标签的document.write调用。请参见https://developers.google.com/web/updates/2016/08/removing-document-write - Flimm
@Flimm 在上下文中,链接的文档说明“当满足以下所有条件时将不执行注入的脚本标签”。其中之一的条件是要求脚本不来自同一站点。因此,插入来自同一站点的脚本将不会被拒绝。 - traktor

33

优点:

  • 这是从外部脚本嵌入内联内容的最简单方法。
  • 可以覆盖框架/iframe中的整个内容。 在更现代的Ajax技术普及之前(1998-2002),我经常使用这种技术来处理菜单/导航。

缺点:

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

5
还有更多缺点。比如,在某些情况下,Google Chrome会拒绝运行创建<script>标签的document.write。具体请参考https://developers.google.com/web/updates/2016/08/removing-document-write - Flimm
1
@Flimm 值得注意的是,你的评论是在我的回答之后8年,而现在已经过去了将近3年。是的,还有其他的缺点...我会感到惊讶如果document.write本身不会消失...以及可能一些其他被滥用的接口。 - Tracker1

10

总的来说,在进行重量级处理时,通常不应该使用 document.write,但是有一种情况可以明确地使用它:

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

我最近发现这个问题,是因为尝试创建 AJAX 滑动画廊。 我创建了两个嵌套的 div,并在外部 <div> 上应用了 width/heightoverflow: hidden 的 JS。 这样,如果浏览器禁用了 JS,该 div 将浮动以适应画廊中的图像 - 一些不错的优雅降级。

问题是,就像上面的文章一样,这种对 CSS 的 JS 劫持直到页面加载后才能生效,从而导致 div 加载时出现短暂闪烁。 所以我需要编写一个 CSS 规则或在页面加载时包含样式表。

显然,这在 XHTML 中不起作用,但由于 XHTML 似乎已经过时(并且在 IE 中呈现为标签 soup),所以重新评估 DOCTYPE 的选择可能是值得的...


7

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

除非您正在使用JavaScript创建整个文档,否则它没有太多用途,在这种情况下,您可以从document.write开始。

即使如此,当您使用document.write时,实际上并没有充分利用DOM-您只是将一大块文本倾泻到文档中,因此我认为这是不好的形式。


2
一个澄清:document.write会在页面上插入内容,而不是覆盖它们。 - Peter Dolberg
5
如果您在文档加载后调用它,它将覆盖内容。我猜这就是aleemb的意思。@Peter - Matthew Crumley
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开发人员提倡的方法完全相反。 - Lèse majesté

7

以下是我脑海中的想法:

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

  2. 从技术上讲,document.write只会更新HTML页面而不是XHTML/XML。IE似乎对此事情很宽容,但其他浏览器将不会。

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


9
IE很宽容,因为它不支持XHTML。如果/当它们支持XHTML时,document.write可能会停止工作(当然只针对XHTML)。 - Matthew Crumley
2
XHTML在网络上已经不重要了。即使是具有严格XHTML文档类型的页面,在这方面也不会被视为XML,浏览器开发人员并不完全信任页面作者。 - RobG

7

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

最好的情况:一些浏览器会切换回HTML渲染,一切正常。

可能的情况:一些浏览器在XML渲染模式下禁用document.write()函数。

最糟糕的情况:一些浏览器在使用document.write()函数时会触发XML错误。


5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接