使用远程加载的JavaScript中的document.write来编写内容——为什么是个坏主意?

5
我不是一名全职的Javascript开发者。我们有一个Web应用程序,其中一个部分是将一个小型信息窗口小部件写入到另一个域中。这实际上只是一个HTML表格,其中写出了一些值。在过去的8年里,我不得不做过几次这样的事情,我总是通过一个脚本来完成,该脚本只是使用document.write输出表格。
例如:
document.write('<table border="1"><tr><td>here is some content</td></tr></table>');

在他们的域名网站上

<body>
....
<script src='http://ourdomain.com/arc/v1/api/inventory/1' type='text/javascript'></script>
.....
</body>

我一直认为这有点丑陋,但它工作得很好,我们总是可以控制内容(或者可信的代表可以控制,例如您当前的库存或其他类似的东西)。所以又出现了另一个类似的项目,我使用document.write在大约5分钟内编写了它。有人认为这太丑陋了,但我不知道问题出在哪里。关于小部件方面,我也做过iframe和jsonp实现,但是iframe往往与其他网站的css不兼容,而jsonp往往会导致负担过重。我是否忽略了某些安全因素?还是说我所做的都可以?什么是使用此技术的最强论据?我是否需要了解最佳实践?


性能、无 JS 和 SEO 是主要的抱怨。有些人似乎出于个人原因不喜欢它... - dandavis
1
如果您的远程脚本未同步加载,它将会崩溃得非常严重。在重新设计包含页面时,这将是一个问题。 - Bergi
1
@Bergi 崩溃了?还是只是没有渲染?如果这样的话,完全可以接受,因为这与 jsonp 或 iframe 解决方案相同。 - timpone
@bergi:没错。innerHTML 选项更好,但从哲学上讲,它们是相同的概念。然而,一旦你将ID或URL硬编码到远程脚本中并处理旧版IE,它就失去了很多简单性... - dandavis
感谢@Bergi - 我们将会有一个连接的字符串,但希望不会太糟糕。现在正在研究是否应该使用异步方法。 - timpone
显示剩余3条评论
3个回答

4
说实话,我并没有看出什么问题。是的,document.write非常老派,但它简单易用,并且在所有浏览器中都有普遍支持;你可以相信它在每个浏览器中的工作方式都是相同的。
对于您的应用程序(编写带有某些数据的HTML表),我认为如果您愿意承担一些小风险,就不需要更复杂的解决方案。如果您没有使用jQuery等库,要处理跨浏览器正确工作的DOM突变是一件不容易做对的事情。 document.write的风险:
  • 您的脚本必须同步加载。这意味着正常的内联脚本标签(就像您已经在使用的)。 但是,如果有人聪明地给您的脚本标签添加了asyncdefer属性, 或者做了一些高级的事情,例如将动态创建的script元素添加到中),您的脚本将异步加载。

    这意味着当您的脚本最终加载并调用write时,主文档可能已经完成加载,并且文档已“关闭”。在关闭的文档上调用write会隐式调用open,它将完全清除DOM——实际上就像擦掉页面并重新开始。您不希望出现这种情况。

  • 由于您的脚本是同步加载的,您要让第三方页面依靠您的服务器。如果您的服务器崩溃或负载过高且响应缓慢,则包含您的脚本标签的每个页面无法完成加载,直到您的服务器做出响应或浏览器超时请求。

    放置您的小部件的网站所有者将不会感到满意。

如果您对服务器正常运行时间有信心,那么没有理由改变您当前的做法。
另一种方法是异步加载您的脚本,并将表格插入到DOM的正确位置。这意味着第三方必须同时插入脚本片段(使用<script async src="...">或使用动态脚本标记插入技巧)。他们还需要为您提供一个专门的
来放置您的表格。

感谢@josh3736的回答,关于你第一个要点中第二段所提到的问题。按照我目前的构建方式,这会有问题吗?如果我们假设服务器返回时间为300毫秒,页面剩余部分加载时间为10毫秒(即远程document.write在完成后290毫秒开始),这会导致主页面被覆盖吗?虽然我没有在实践中看到过这种情况,但这显然是我最担心的问题。 - timpone
关于第二点,我同意这是一个合理的担忧,但任何远程加载数据都会如此,还是有特定的实现方式使其特别脆弱吗?异步脚本建议听起来非常可靠。让我更深入地研究一下 - 这是你建议的吗?非常感谢您的回答。 - timpone
@timpone:整个重点在于,按照你现在的代码,它是同步加载和执行的。浏览器在脚本加载期间停止执行任何其他操作,因此无论您的服务器是否在300毫秒或一分钟内响应都无关紧要。至于#2,这是由于遗留问题而使<script>标签具有独特属性。最初的Netscape就是这样做的(同步),而浏览器之所以仍然这样做,正是因为否则会破坏这种(仍然常见的)使用document.write的方法。如果您切换到异步加载方法,则不能使用document.write - josh3736
谢谢你的澄清。我只是想确保我理解你的意思没有错。 - timpone

2

1
这没有意义。当在打开的文档上调用document.write()(即从同步<script>中调用,就像OP正在做的那样)时,它不会对DOM做任何事情。您仍然可以正常访问它。您链接到的线程正在讨论异步调用document.write,这很可能会在文档关闭后发生。在这种情况下,DOM被清除。 - josh3736
这在这个JSFiddle(http://jsfiddle.net/2Z3cZ/)上有效地工作...我一直都是这样想的...(但不是在这个上面:http://jsfiddle.net/2Z3cZ/2/) - cubitouch
感谢@cubitouch提供的jsfiddle - 当您说访问DOM时,是指编写的HTML的DOM还是页面中的任何DOM。以问题中的简单表格为例; 我不想向该DOM添加任何内容,但我是否能够对页面的其余部分进行DOM操作? - timpone
在这种情况下,它似乎是无害的。但在我看来,这似乎是一种不好的做法,因为你是在处理文本而不是对象。 - cubitouch

2

我是否缺少某些安全元素?

对于他们来说,安全风险在于 theirdomain.com 相信你的域名脚本代码不会做任何恶意行为。您的客户端脚本将在其域中运行,可以随意执行操作,例如窃取 cookie 或嵌入键盘记录器(当然您不会这样做)。只要他们信任您,那就没问题。


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