添加

最近我看到一些 HTML 在其 中只有一个

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

这个 script.js 然后添加使用 document.write(...) 将任何其他必要的

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 CSS 文件> 和 script.js 只添加由支持 JS 的用户代理使用的所有 CSS 和 JavaScript。

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

Recently I saw some HTML with only a single <script> element in its <head>...

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

This script.js then adds any other necessary <script> elements and <link> elements to the document using document.write(...): (or it could use document.createElement(...) etc)

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>")

Note that there is a plain.css CSS file in the document <head> and script.js just adds any and all CSS and JavaScript which would be used by a JS-enabled user agent.

What are some of the pros and cons of this technique?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

离旧人 2024-10-29 04:39:20

document.write 的阻塞性质

document.write 将暂停浏览器在页面上进行的所有操作(包括解析)。由于这种阻塞行为,强烈建议避免。浏览器无法知道此时您要向 HTML 文本流中写入什么内容,或者写入是否会完全丢弃 DOM 树上的所有内容,因此它必须停止,直到您完成为止。

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

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

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

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

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

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

当 document.write 正在进行时,浏览器无法继续解析 HTML,在某些情况下,由于 document.write 的阻塞行为,当编写的脚本正在执行时,因此您的页面会显示慢得多。

换句话说,您的网站的加载速度就像在没有优化的几十年前的浏览器上加载一样慢。

为什么有人会这样做?

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

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

一些解决方案

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

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

The blocking nature of document.write

document.write will pause everything that the browser is working on the page (including parsing). It is highly recommended to avoid because of this blocking behavior. The browser has no way of knowing what you're going to shuff into the HTML text stream at that point, or whether the write will totally trash everything on the DOM tree, so it has to stop until you're finished.

Essentially, loading scrips this way will force the browser to stop parsing HTML. If your script is in-line, then the browser will also execute those scripts before it goes on. Therefore, as a side-note, it is always recommended that you defer loading scripts until after your page is parsed and you've shown a reasonable UI to the user.

If your scripts are loaded from separate files in the "src" attribute, then the scripts may not be consistently executed across all browsers.

Losing browser speed optimizations and predictability

This way, you lose a lot of the performance optimizations made by modern browsers. Also, when your scripts execute may be unpredictable.

For example, some browsers will execute the scripts right after you "write" them. In such cases, you lose parallel downloads of scripts (because the browser doesn't see the second script tag until it has downloaded and executed the first). You lose parallel downloads of scripts and stylesheets and other resources (many browsers can download resources, stylesheets and scripts all at the same time).

Some browsers defer the scripts until after the end to execute them.

The browser cannot continue to parse the HTML while document.write is going on and, in certain cases, when the scripts written are being executed due to the blocking behavior of document.write, so your page shows up much slower.

In other words, your site has just become as slow as it was loading on a decades-old browser with no optimizations.

Why would somebody do it like this?

The reason you may want to use something like this is usually for maintainability. For instance, you may have a huge site with thousands of pages, each loading the same set of scripts and stylesheets. However, when you add a script file, you don't want to edit thousands of HTML files to add the script tags. This is particularly troublesome when loading JavaScript libraries (e.g. Dojo or jQuery) -- you have to change each HTML page when you upgrade to the next version.

The problem is that JavaScript doesn't have an @include or @import statement for you to include other files.

Some solutions

The solution to this is probably not by injecting scripts via document.write, but by:

  1. Using @import directives in stylesheets
  2. Using a server scripting language (e.g. PHP) to manage your "master page" and to generate all other pages (however, if you can't use this and must maintain many HTML pages individually, this is not a solution)
  3. Avoid document.write, but load the JavaScript files via XHR, then eval() them -- this may have security concerns though
  4. Use a JavaScript Library (e.g. Dojo) that has module-loading features so that you can keep a master JS file which loads other files. You won't be able to avoid having to update the version numbers of the library file though...
我是男神闪亮亮 2024-10-29 04:39:20

一大缺点是浏览器不兼容。并非所有浏览器都能正确获取资源并将其合并到 DOM 中,因此使用这种方法是有风险的。样式表比脚本更是如此。

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

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

One major disadvantage is browser incompatibility. Not all browsers correctly fetch and incorporate the resources into the DOM, so it's risky to use this approach. This is more true of stylesheets than scripts.

Another issue is one of maintainability. Concatenating and writing strings to add DOM elements on the client'side can become a maintenance nightmare. It's better to use DOM methods such as createElement to semantically create elements.

One obvious advantage is that it makes conditional use of resources much easier. You can have logic that determines which resources to load, thereby reducing the bandwidth consumption and overall processing time for the page. I would use a library call such as jQuery $.getScript() to load scripts versus document.write. The advantage being that such an approach is cleaner and also allows you to have code executed when the request is completed or fails.

陈甜 2024-10-29 04:39:20

好吧,我不妨向这个致敬……

如果你检查 google 的闭包库,base.js,你会发现在他们的 writeScriptTag_() 中使用了 document.write功能。这是“闭包”提供的依赖管理系统的重要组成部分,并且在创建复杂的、多文件的、基于库的 JavaScript 应用程序时具有巨大的优势 - 它让文件/代码先决条件确定加载顺序。我们目前使用这种技术并且几乎没有遇到什么问题。老实说,我们没有遇到任何浏览器兼容性问题,并且我们定期在 IE 6/7/8、FF3/2、Safari 4/5 和最新的 Chrome 上进行测试。

到目前为止,我们遇到的唯一缺点是,追踪由于加载资源两次或根本加载失败而导致的问题可能具有挑战性。由于加载资源的行为是编程性的,因此可能会出现编程错误,并且与直接将标签添加到 HTML 不同,很难看出确切的加载顺序。然而,这个问题可以通过使用具有某种形式的依赖管理系统(例如闭包或dojo)的库来很大程度上解决。

编辑:我对此性质做了一些评论,但我认为最好在我的回答中总结一下:
dojo.require() 和 jQuery.getScript() (两者最终都会执行 ajax 请求和 eval)存在一些问题。

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

Well, I may as well throw my hat in the ring on this one...

If you examine google's closure library, base.js, you will see that document.write is used in their writeScriptTag_() function. This is an essential part of the dependency management system which 'closure' provides, and is an enormous advantage when creating a complicated, multi-file, library-base javascript application - it lets the file/code prerequisites determine loading order. We currently use this technique and have been having little trouble with it. TBH, we have not had a single issue with browser compatibility, and we test regularly on IE 6/7/8, FF3/2, Safari 4/5 and Chrome latest.

The only disadvantage that we have had so far is that it can be challenging to track down issues caused by loading a resource twice, or failing to load one at all. Since the act of loading resources is programmatic, it is subject to programmatic errors, and unlike adding the tags directly to the HTML, it can be hard to see what the exact loading order is. However, this issue can be largely overcome by using a library with some form of dependency management system such as closure, or dojo.

EDIT: I have made a few comments to this nature, but I thought it best to summarize in my answer:
There are some problems with dojo.require() and jQuery.getScript() (both which ultimiately perform an ajax request and eval).

  1. loading via ajax means no cross scripting - ie no loading javascript that is not from your site. This will be a problem if you want to include https://ajax.googleapis.com as listed in the description.
  2. Eval'd scripts will not show up in a javascript debugger's list of page scripts, making debugging quite challenging. Recent releases of firebug will show you eval'd code, however filenames are lost making the act of setting breakpoints tedious. AFAIK, Webkit javascript console and IE8 developer tools do not show eval'd scripts.
翻身的咸鱼 2024-10-29 04:39:20

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

It has the advantage that you don't need to repeat the script references in each HTML file. The disadvantage is that the browser must fetch and execute the main javascript file before it may load the others.

策马西风 2024-10-29 04:39:20

我想我能想到的一个优点是,如果您在多个页面上使用这些脚本,您只需要记住包含一个脚本,并且它可以节省一些空间。

I guess one advantage I could think of would be if you use these scripts on multiple pages, you only have to remember to include one script, and it saves some space.

凉薄对峙 2024-10-29 04:39:20

在 Google PageSpeed,他们强烈建议您不要使用此技术,因为它会使速度变慢。除了在所有其他脚本之前顺序加载 script.js 之外,还有另一个问题:

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

At Google PageSpeed, they highly discourage you from using this technique, because it makes things slower. Apart from the sequential loading of your script.js before all the others, there's another catch:

Modern browsers use speculative parsers to more efficiently discover external resources [...] Thus, using JavaScript's document.write() to fetch external resources makes it impossible for the speculative parser to discover those resources, which can delay the download, parsing, and rendering of those resources.

梦毁影碎の 2024-10-29 04:39:20

这也可能是 SEO 公司的建议,如果可能的话,让 head 元素更短,这样独特的内容更接近文档的顶部 - 也创造了更高的文本与 HTML 的比率。尽管总而言之,这听起来确实不是一个很好的方法;尽管这会使维护更加耗时,但如果认为完全有必要减少头元素大小,更好的方法可能是将 javascript 压缩为单个 .js 文件,将 css 压缩为单个 .css 文件。

It's also possible that this was written as a recommendation by an SEO firm to make the head element shorter if possible, so unique content is closer to the top of the document - also creating a higher text-to-HTML ratio. Though it does sound, all-in-all, like not a very good way of doing this; though it would make maintenance more time-consuming, a better approach would probably be to condense javascript into a single .js file and css into a single .css file, if it were deemed utterly necessary to reduce head element size.

与君绝 2024-10-29 04:39:20

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

现在,建议您将脚本标签放在 之前。当然,这不可能 100% 成功,但如果您使用 unobtrusve Javascript(正如您应该的那样),所有脚本都可以在文档末尾重新定位。

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

我建议不惜一切代价反对使用document.write。即使没有它,这也会导致向服务器发出一个额外的请求。 (我们喜欢最大化请求数量,例如使用 css sprites.)

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

A great disadvantage is that adding scripts into head will pause the processing of the document until those scripts were completely downloaded parsed and executed (because the browser thinks they may use document.write). - This will hurt responsiveness.

Now days it is recommended that you put your script tags right befo </body>. Of course this is not possible 100% of times, but if you are using unobtrusve Javascript (as you should), all scripts can be respositioned at the end of the document.

HTML5 came up with the async attribute which suggests the browser only to execute the scripts after the main document has been loaded. This is the behaviour of script-inserted scripts in many browsers, but notin all of them.

I advise against using document.write at all costs. Even without it, this results in one extra request towards the server. (We like to inimze the number of requests, for example with css sprites.)

And yes, as others mentioned earlier, if scriping is disabled your page will be shown without CSS (which makes it potentially unusable).

我偏爱纯白色 2024-10-29 04:39:20
  1. 如果 JavaScript 禁用 -

  2. 如果您将 JavaScript 初始化函数放在页面底部(这是一个很好的做法)并将 CSS 与 JavaScript 链接起来,则可能会在 CSS 加载之前造成一些延迟(在短时间内会看到损坏的布局)。

  1. If JavaScript is disabled - <script> and <link> elements won't be added at all.

  2. If you place JavaScript init functions at the bottom of your page (which is a good practice) and link CSS with JavaScript, it may cause a some delay before CSS loads (broken layout will be visible for a short time).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文