使用JavaScript添加<script>和<link>元素的优缺点是什么?</script>

时间:2011-03-14 18:15:40

标签: javascript css dom progressive-enhancement

最近我看到一些HTML <script>只有一个<head>元素...

<head>
    <title>Example</title>
    <script src="script.js" type="text/javascript"></script>
    <link href="plain.css" type="text/css" rel="stylesheet" />
</head>

script.js然后使用<script>将任何其他必要的<link>元素和document.write(...)元素添加到文档中:(或者它可以使用document.createElement(...)等)< / p>

document.write("<link href=\"javascript-enabled.css\" type=\"text/css\" rel=\"styleshet\" />");
document.write("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js\" type=\"text/javascript\"></script>");
document.write("<script src=\"https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js\" type=\"text/javascript\"></script>");
document.write("<link href=\"http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/themes/trontastic/jquery-ui.css\" type=\"text/css\" rel=\"stylesheet\" />")
document.write("<script src=\"validation.js\" type=\"text/css\"></script>")

请注意,文档plain.css中有<head>个CSS文件,而script.js只添加了启用了JS的用户代理将使用的所有CSS和JavaScript。< / p>

这种技术有哪些优点和缺点?

9 个答案:

答案 0 :(得分:12)

document.write的阻止性质

document.write将暂停浏览器在页面上工作的所有内容(包括解析)。由于此阻止行为,强烈建议避免。浏览器无法知道你在那个时候会对HTML文本流的影响,或者写入是否会完全删除DOM树上的所有东西,所以它必须在你完成之前停止。

基本上,以这种方式加载scrips会强制浏览器停止解析HTML。如果您的脚本是内联的,那么浏览器也会在它们继续运行之前执行这些脚本。因此,作为附注,始终建议您延迟加载脚本,直到解析页面后,并且您已向用户显示合理的UI。

如果您的脚本是从“src”属性中的单独文件加载的,那么脚本可能无法在所有浏览器中一致地执行。

失去浏览器速度优化和可预测性

这样,您就失去了现代浏览器所做的许多性能优化。此外,当您的脚本执行时可能无法预测。

例如,某些浏览器会在您“编写”它们之后立即执行脚本。在这种情况下,您将失去脚本的并行下载(因为浏览器在下载并执行第一个脚本标记之前不会看到第二个脚本标记)。您将失去脚本和样式表以及其他资源的并行下载(许多浏览器可以同时下载资源,样式表和脚本)。

有些浏览器将脚本推迟到结束后执行它们。

当document.write正在进行时,浏览器无法继续解析HTML,在某些情况下,由于document.write的阻止行为而导致执行的脚本正在执行时,因此您的页面显示速度要慢得多

换句话说,您的网站变得与在数十年前没有优化的浏览器上加载一样慢。

为什么有人会这样做?

您可能希望使用此类内容的原因通常是为了可维护性。例如,您可能拥有一个包含数千个页面的大型站点,每个页面都加载了相同的脚本和样式表集。但是,添加脚本文件时,您不希望编辑数千个HTML文件来添加脚本标记。这在加载JavaScript库(例如Dojo或jQuery)时尤其麻烦 - 在升级到下一个版本时必须更改每个HTML页面。

问题是JavaScript没有@include或@import语句供您包含其他文件。

一些解决方案

解决方法可能不是通过document.write注入脚本,而是通过:

  1. 在样式表中使用@import指令
  2. 使用服务器脚本语言(例如PHP)来管理“母版页”并生成所有其他页面(但是,如果您不能使用它并且必须单独维护许多HTML页面,则这不是解决方案)< / LI>
  3. 避免使用document.write,但是通过XHR加载JavaScript文件,然后使用eval()加载它们 - 这可能存在安全问题
  4. 使用具有模块加载功能的JavaScript库(例如Dojo),以便您可以保留加载其他文件的主JS文件。您将无法避免必须更新库文件的版本号...

答案 1 :(得分:8)

一个主要缺点是浏览器不兼容。并非所有浏览器都正确地获取并将资源合并到DOM中,因此使用此方法存在风险。样式表比脚本更真实。

另一个问题是可维护性。连接和编写字符串以在客户端添加DOM元素可能会成为维护的噩梦。最好使用DOM方法(如createElement)来语义创建元素。

一个明显的优点是它使资源的有条件使用变得更加容易。您可以使用逻辑来确定要加载的资源,从而减少页面的带宽消耗和总体处理时间。我会使用诸如jQuery $ .getScript()之类的库调用来加载脚本与document.write。优点是这种方法更清晰,并且允许您在请求完成或失败时执行代码。

答案 2 :(得分:8)

好吧,我也可以把这顶帽子放在戒指上......

如果你检查google的闭包库base.js,你会看到document.write在他们的writeScriptTag_()函数中使用。这是“闭包”提供的依赖管理系统的一个重要部分,并且在创建复杂的,多文件的,基于库的javascript应用程序时是一个巨大的优势 - 它允许文件/代码先决条件确定加载顺序。我们目前使用这种技术,并没有遇到任何问题。 TBH,我们没有一个浏览器兼容性问题,我们定期测试IE 6/7/8,FF3 / 2,Safari 4/5和Chrome最新版本。

到目前为止,我们唯一的缺点是,追踪因加载资源两次或根本无法加载资源而导致的问题可能具有挑战性。由于加载资源的行为是程序化的,因此它会受到编程错误的影响,而且与将标记直接添加到HTML中不同,很难看出确切的加载顺序是什么。但是,通过使用具有某种形式的依赖关系管理系统(如closure或dojo)的库,可以在很大程度上克服此问题。

编辑:我已就这种性质发表了一些评论,但我认为最好总结一下我的答案: dojo.require()和jQuery.getScript()都存在一些问题(两者都最终执行ajax请求和eval)。

  1. 通过ajax加载意味着没有交叉脚本 - 即没有加载不是来自您网站的JavaScript。如果您想要包含说明中列出的https://ajax.googleapis.com,这将是一个问题。
  2. Eval'd脚本不会出现在javascript调试器的页面脚本列表中,这使得调试非常具有挑战性。最近发布的firebug将显示eval'd代码,但文件名丢失使得设置断点的行为变得乏味。 AFAIK,Webkit javascript控制台和IE8开发人员工具显示eval'd脚本。

答案 3 :(得分:4)

它的优点是您不需要在每个HTML文件中重复脚本引用。缺点是浏览器必须获取并执行主javascript文件才能加载其他文件。

答案 4 :(得分:2)

我想我能想到的一个好处就是如果你在多个页面上使用这些脚本,你只需记住包含一个脚本,它就可以节省一些空间。

答案 5 :(得分:2)

在Google PageSpeed,他们强烈反对您使用此技术,因为它会让事情变得更慢。除了在所有其他人之前顺序加载 script.js 之外,there's another catch:

  

现代浏览器使用推测解析器来更有效地发现外部资源[...]因此,使用JavaScript的document.write()来获取外部资源使得推测解析器无法发现那些可能会延迟下载的资源,解析和渲染这些资源。

答案 6 :(得分:2)

这也可能是由SEO公司推荐的,以便尽可能缩短头部元素,因此独特的内容更接近文档的顶部 - 同时创建更高的文本与HTML比率。虽然它确实听起来,但总的来说,并不是一个非常好的方式;虽然它会使维护更耗时,但更好的方法可能是将javascript压缩为单个.js文件并将css压缩为单个.css文件,如果认为完全有必要减少头元素大小。

答案 7 :(得分:1)

一个很大的缺点是将script添加到head中会暂停文档的处理,直到这些脚本被完全下载解析并执行(因为浏览器认为它们可能使用document.write)。 - 这会伤害响应能力。

现在,建议您将脚本标记设置为befo </body>。当然,这不可能100%,但如果您使用 unobtrusve Javascript (如您所愿),所有脚本都可以在文档末尾重新定位。

HTML5提出了async属性,该属性建议浏览器仅在加载主文档后执行脚本。这是脚本插入脚本在许多浏览器中的行为,但并不是所有浏览器中的行为。

我不惜一切代价使用document.write建议反对。即使没有它,这也会导致对服务器的一个额外请求。 (我们希望模仿请求的数量,例如使用css sprites。)

是的,正如其他人之前提到的,如果禁用了脚本,您的页面将显示没有CSS(这使得它可能无法使用)。

答案 8 :(得分:0)

  1. 如果JavaScript 已禁用 - 则根本不会添加<script> and <link>个元素。

  2. 如果您将JavaScript初始化函数放在页面底部(这是一个很好的做法)并将CSS与JavaScript链接,那么在加载CSS之前可能会导致一些延迟(破坏的布局会在短时间内显示)。