【问题标题】:Why is document.write considered a "bad practice"?为什么 document.write 被认为是“不好的做法”?
【发布时间】:2010-10-22 14:49:23
【问题描述】:

我知道document.write 被认为是不好的做法;我希望编制一份提交给第 3 方供应商的理由列表,说明他们为什么不应该在其分析代码的实现中使用 document.write

请在下面说明您声称 document.write 是一种不良做法的原因。

【问题讨论】:

    标签: javascript


    【解决方案1】:

    一些更严重的问题:

    • document.write(以下简称 DW)在 XHTML 中不起作用

    • DW 不直接修改 DOM,防止进一步操作 (试图找到证据,但最好是根据情况)

    • 页面加载完成后执行的DW会覆盖页面,或者写一个新页面,或者不起作用

    • DW 在遇到的地方执行:它不能在给定的节点点注入

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

    最好使用安全且对 DOM 友好的 DOM manipulation methods

    【讨论】:

    • -1,它绝对修改了 DOM。其他一切都很好。虽然我理解依靠结构和方法来保护您免受伤害的冲动,但这可能是一种将婴儿与洗澡水一起扔掉的情况。
    • FireBug 不是 DOM 的真实表示。 Mozilla 尝试将 HTML 解析为 DOM。您可以在 Firebug DOM 视图中显示完全损坏的 HTML。
    • DOM 是用于呈现页面的数据结构,因此是用户在页面上看到的内容的 alpha 和 omega。 HTML != DOM 是正确的,但是对于 DW 是否修改 DOM 的问题并不重要。如果 DW 没有修改 DOM,您就看不到屏幕 - 所有浏览器都是如此,只要 DOM 是用于呈现页面的东西,就会一直如此。
    • “DW 在遇到的地方执行” - 并不总是一个缺点,实际上它可以被认为是某些事情的优点,例如,添加脚本元素(实际上是我唯一的事情'd 使用 DW,即使那样我也会三思而后行)。
    • @RicardoRivaldo 是的,如果在文档完成加载后调用 document.write,他们会这样做
    【解决方案2】:

    document.write 本身并没有什么问题。问题是它真的很容易被滥用。大体上,甚至。

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

    1. 它使脚本更小
    2. 他们不必担心覆盖已建立的 onload 事件或包含必要的抽象来安全地添加 onload 事件
    3. 非常兼容

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

    【讨论】:

    • document.write 对 html 解析器做了非常可怕的事情,并且仅在简单的情况下“非常兼容”。
    • 喜欢插入分析标签?毕竟,那是原始问题的一部分。并且非常兼容,我的意思是仅对 document.write 方法的原始浏览器支持。
    • 任何与最新版本的 Chrome / IE / Safari / Opera / FireFox 兼容的东西都被认为是兼容的。
    • 覆盖加载事件? addEventListener 是干什么用的?
    • Chrome 将不会运行document.write 调用,这些调用会在满足某些条件时插入脚本。
    【解决方案3】:

    它会屏蔽你的页面

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

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

    【讨论】:

      【解决方案4】:

      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 (needed by IE7 and below) 的相同技术。

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

      【讨论】:

      • 在这里使用还不错,但使用 DOM 操作功能仍然“更好”——甚至谷歌也为谷歌分析做了它。片段是here
      • @BMiner 如果您通过 DOM 操作插入 script 元素,它会同步加载吗?除非是,否则它不是替代品。
      • @JanDvorak - 好点;当使用 DOM 操作时,浏览器通常会异步加载脚本。您可以使用onload DOM 事件来确定异步加载的脚本何时可用。
      • @JanDvorak It is loaded synchronously if it isn't external (doesn't have src)。否则它将“尽快”异步执行。
      • 这仍然会中断,因为如果用户使用 2G 连接,Chrome 会故意拒绝运行插入 &lt;script&gt; 标签的 document.write 调用。见developers.google.com/web/updates/2016/08/…
      【解决方案5】:

      专业版:

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

      缺点:

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

      【讨论】:

      • 还有更多的缺点。例如,谷歌浏览器在某些情况下会拒绝运行创建&lt;script&gt; 标签的document.writedevelopers.google.com/web/updates/2016/08/…
      • @Flimm 值得注意的是,您的评论是在我回答之后 8 年多,而这几乎是 3 年后。是的,还有其他缺点……如果 document.write 本身没有消失,我会感到惊讶……以及其他一些被高度滥用的接口。
      【解决方案6】:

      这是我的两便士,一般来说,您不应该使用document.write 进行繁重的工作,但有一个实例绝对有用:

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

      我最近在尝试创建 AJAX 滑块库时发现了这一点。我创建了两个嵌套的 div,并使用 JS 将 width/heightoverflow: hidden 应用于外部 &lt;div&gt;。这样一来,在浏览器禁用 JS 的情况下,div 会浮动以容纳图库中的图像 - 一些不错的优雅降级。

      问题是,和上面的文章一样,这个 JS 劫持 CSS 直到页面加载后才开始,导致加载 div 时瞬间闪烁。所以我需要在页面加载时编写一个 CSS 规则,或者包含一个工作表。

      显然,这在 XHTML 中不起作用,但由于 XHTML 看起来有点像死鸭(在 IE 中呈现为标签汤),因此可能值得重新评估您对 DOCTYPE 的选择...

      【讨论】:

        【解决方案7】:

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

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

        即便如此,当您使用 document.write 时,您并没有真正利用 DOM——您只是将一团文本转储到文档中,所以我会说这是一种糟糕的形式。

        【讨论】:

        • 一个澄清:document.write 在页面上插入内容,它不会覆盖它们。
        • @Peter,如果您在加载文档后调用它,它会覆盖内容。我猜这就是 aleemb 的意思。
        • 您是否建议应该在代码中手动构建单个 DOM 节点,而不是像 div.innerHTML = "&lt;label for='MySelect'&gt;Choose One&lt;/label&gt;&lt;select id='MySelect'&gt;&lt;option value='foo' selected=''&gt;foo&lt;/option&gt;&lt;option value='bar'&gt;bar&lt;/option&gt;&lt;/select&gt;"; 这样的事情?这似乎会产生很多不必要且可读性较差的代码。这也与 John Resig 和其他 JS 开发人员提倡的方法完全相反。
        【解决方案8】:

        它使用 XML 呈现来破坏页面(如 XHTML 页面)。

        最佳:一些浏览器切换回 HTML 渲染,一切正常。

        很可能:某些浏览器在 XML 渲染模式下禁用了 document.write() 函数。

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

        【讨论】:

          【解决方案9】:

          在我的头顶:

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

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

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

          【讨论】:

          • IE 是宽容的,因为它不支持 XHTML。如果/当他们这样做时,document.write 可能会停止工作(当然只在 XHTML 中)。
          • XHTML 与网络无关。在这方面,即使具有严格 XHTML 文档类型的页面实际上也不会被视为 XML,浏览器开发人员也不太信任页面作者那么
          【解决方案10】:

          Chrome 可能会阻止 document.write 在某些情况下插入脚本。发生这种情况时,它将在控制台中显示此警告:

          一个解析器阻塞的跨域脚本,...,通过以下方式调用 文件。写。如果设备有这可能会被浏览器阻止 网络连接不佳。

          参考资料:

          【讨论】:

            【解决方案11】:

            浏览器违规

            .write 被视为浏览器违规,因为它会停止解析器呈现页面。解析器接收到文档正在被修改的消息;因此,它会被阻塞,直到 JS 完成它的进程。只有此时解析器才会恢复。

            性能

            采用这种方法的最大后果是性能下降。浏览器将需要更长的时间来加载页面内容。对加载时间的不利反应取决于写入文档的内容。如果您向 DOM 添加 &lt;p&gt; 标记而不是向 JavaScript 库传递一个包含 50 个引用的数组(我在工作代码中看到并导致 11 秒延迟 - 当然,这也取决于您的硬件)。

            总而言之,如果你能提供帮助,最好避开这种方法。

            更多信息见Intervening against document.write()

            【讨论】:

              【解决方案12】:

              基于 Google-Chrome Dev Tools'Lighthouse Audit 所做的分析,

              对于连接速度较慢的用户,通过document.write() 动态注入的外部脚本可以将页面加载延迟数十秒。

              【讨论】:

                【解决方案13】:
                • document.write 是一种不好的做法的一个简单原因是,您无法想出一个找不到更好替代方案的方案。
                • 另一个原因是您处理的是字符串而不是对象(它非常原始)。
                • 它只附加到文档。
                • 它没有MVC (Model-View-Controller) 模式的美感。
                • 使用ajax+jQueryangularJS 呈现动态内容要强大得多。

                【讨论】:

                • 至于你的第一颗子弹,你将如何解决@sunwukung 在他上面的回答中描述的问题?我同意你可以通过 DOM 操作来解决它,但是随着 DOM 操作的进行,如果没有document.write,有时很难避免 FUOC。
                • FUOC 不再是问题了吗?
                【解决方案14】:

                我不认为使用 document.write 是一个坏习惯。简而言之,对于没有经验的人来说,它就像一个高压。如果你用错了方法,你就会被煮熟。有许多开发人员至少使用过一次这种和其他危险的方法,但他们从未真正深入挖掘他们的失败。相反,当出现问题时,他们只是退出,并使用更安全的东西。那些对所谓的“不良做法”发表此类声明的人。

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

                【讨论】:

                  【解决方案15】:

                  可以将 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/

                  【讨论】:

                    【解决方案16】:

                    document.write的缺点主要取决于这3个因素:

                    a) 实施

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

                    b) 渲染

                    设计良好的代码通常会获取任何动态生成的内容,将其存储在内存中,并在代码通过代码时不断对其进行操作,然后最终将其吐出到屏幕上。因此,重申上一节中的最后一点,就地渲染内容可能比可能依赖的其他内容渲染得更快,但它可能不适用于其他需要渲染内容以进行处理的代码。为了解决这个难题,我们需要摆脱 document.write() 并以正确的方式实现它。

                    c) 不可能的操作

                    一旦写完,就结束了。如果不利用 DOM,我们就无法回去操作它。

                    【讨论】:

                      【解决方案17】:

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

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

                      【讨论】:

                      • 这不是真的。 document.write 不会像追加内容一样将内容添加到页面末尾。它们写在适当的位置。
                      • @Peter Bailey,我知道这是一个旧线程,但实际上这不应该被否决。是否附加取决于 document.write() 在页面加载时是否内联运行。如果在页面加载后从函数调用它,则第一个 document.write() 将替换整个正文,后续调用将附加到它。
                      • @Octopus 是的,但这是间接的。它仅在该场景中附加,因为有一个新文档。说“document.write() appends”仍然不准确。是的,这是一个旧的答案和一个旧的投票,但我仍然支持它。
                      • 没关系。我说得不准确。我早就会编辑它,但上面有一个更好的答案。我要指出,尽管“就地编写”同样不精确。
                      • document.write 渲染后替换脚本标签。
                      猜你喜欢
                      • 2011-11-20
                      • 2010-11-04
                      • 2022-07-05
                      • 2012-05-18
                      • 2013-10-27
                      相关资源
                      最近更新 更多