Javascript <script defer="defer"> 究竟是如何工作的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5250412/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How exactly does <script defer="defer"> work?
提问by pimvdb
I have a few <script>
elements, and the code in some of them depend on code in other <script>
elements. I saw the defer
attribute can come in handy here as it allows code blocks to be postponed in execution.
我有几个<script>
元素,其中一些元素中的代码依赖于其他<script>
元素中的代码。我看到该defer
属性在这里可以派上用场,因为它允许代码块在执行中被推迟。
To test it I executed this on Chrome: http://jsfiddle.net/xXZMN/.
为了测试它,我在 Chrome 上执行了这个:http: //jsfiddle.net/xXZMN/。
<script defer="defer">alert(2);</script>
<script>alert(1)</script>
<script defer="defer">alert(3);</script>
However, it alerts 2 - 1 - 3
. Why doesn't it alert 1 - 2 - 3
?
但是,它会发出警报2 - 1 - 3
。为什么不提醒1 - 2 - 3
?
采纳答案by Mark At Ramp51
UPDATED: 2/19/2016
更新:2/19/2016
Consider this answer outdated. Refer to other answers on this post for information relevant to newer browser version.
认为这个答案已经过时了。有关与较新浏览器版本相关的信息,请参阅此帖子上的其他答案。
Basically, defer tells the browser to wait "until it's ready" before executing the javascript in that script block. Usually this is after the DOM has finished loading and document.readyState == 4
基本上, defer 告诉浏览器在执行该脚本块中的 javascript 之前等待“直到它准备好”。通常这是在 DOM 完成加载并且 document.readyState == 4 之后
The defer attribute is specific to internet explorer. In Internet Explorer 8, on Windows 7 the result I am seeing in your JS Fiddle test page is, 1 - 2 - 3.
defer 属性特定于 Internet Explorer。在 Internet Explorer 8 中,在 Windows 7 上,我在您的 JS Fiddle 测试页中看到的结果是 1 - 2 - 3。
The results may vary from browser to browser.
结果可能因浏览器而异。
http://msdn.microsoft.com/en-us/library/ms533719(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/ms533719(v=vs.85).aspx
Contrary to popular belief IE follows standards more often than people let on, in actuality the "defer" attribute is defined in the DOM Level 1 spec http://www.w3.org/TR/REC-DOM-Level-1/level-one-html.html
与流行的看法相反,IE 遵循标准的频率比人们所承认的要多,实际上“延迟”属性是在 DOM Level 1 规范中定义的http://www.w3.org/TR/REC-DOM-Level-1/level -one-html.html
The W3C's definition of defer: http://www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer:
W3C 对 defer 的定义:http://www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer:
"When set, this boolean attribute provides a hint to the user agent that the script is not going to generate any document content (e.g., no "document.write" in javascript) and thus, the user agent can continue parsing and rendering."
“设置后,这个布尔属性向用户代理提供了一个提示,即脚本不会生成任何文档内容(例如,javascript 中没有“document.write”),因此,用户代理可以继续解析和呈现。”
回答by Alohci
A few snippets from the HTML5 spec: http://w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async
HTML5 规范中的一些片段:http: //w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async
The defer and async attributes must not be specified if the src attribute is not present.
如果 src 属性不存在,则不能指定 defer 和 async 属性。
There are three possible modes that can be selected using these attributes [async and defer]. If the async attribute is present, then the script will be executed asynchronously, as soon as it is available. If the async attribute is not present but the defer attribute is present, then the script is executed when the page has finished parsing. If neither attribute is present, then the script is fetched and executed immediately, before the user agent continues parsing the page.
可以使用这些属性 [async 和 defer] 选择三种可能的模式。如果存在 async 属性,则脚本将在可用时异步执行。如果 async 属性不存在但 defer 属性存在,则在页面完成解析后执行脚本。如果这两个属性都不存在,则在用户代理继续解析页面之前,将立即获取并执行脚本。
The exact processing details for these attributes are, for mostly historical reasons, somewhat non-trivial, involving a number of aspects of HTML. The implementation requirements are therefore by necessity scattered throughout the specification. The algorithms below (in this section) describe the core of this processing, but these algorithms reference and are referenced by the parsing rules for script start and end tags in HTML, in foreign content, and in XML, the rules for the document.write() method, the handling of scripting, etc.
由于历史原因,这些属性的确切处理细节有些重要,涉及 HTML 的许多方面。因此,实施要求必然分散在整个规范中。下面的算法(在本节中)描述了这个处理的核心,但是这些算法引用并被 HTML 中的脚本开始和结束标记的解析规则、外部内容和 XML 中的 document.write 规则所引用() 方法,脚本的处理等。
If the element has a src attribute, and the element has a defer attribute, and the element has been flagged as "parser-inserted", and the element does not have an async attribute:
The element must be added to the end of the list of scripts that will execute when the document has finished parsing associated with the Document of the parser that created the element.
如果元素具有 src 属性,并且元素具有 defer 属性,并且该元素已被标记为“解析器插入”,并且该元素没有 async 属性:
该元素必须添加到脚本列表的末尾,当文档完成与创建该元素的解析器的 Document 相关联的解析时,这些脚本将执行。
回答by Chris Moschini
The real answer is: Because you cannot trust defer.
真正的答案是:因为你不能相信 defer。
In concept, defer and async differ as follows:
在概念上,defer 和 async 的区别如下:
asyncallows the script to be downloaded in the background without blocking. Then, the moment it finishes downloading, rendering is blocked and that script executes. Render resumes when the script has executed.
async允许在后台下载脚本而不会阻塞。然后,在它完成下载的那一刻,渲染被阻止并执行该脚本。脚本执行后,渲染恢复。
deferdoes the same thing, except claims to guarantee that scripts execute in the order they were specified on the page, and that they will be executed after the document has finished parsing. So, some scripts may finish downloading then sit and wait for scripts that downloaded later but appeared before them.
defer做同样的事情,除了保证脚本按照它们在页面上指定的顺序执行,并且它们将在文档完成解析后执行。因此,某些脚本可能会下载完成然后坐等稍后下载但出现在它们之前的脚本。
Unfortunately, due to what is really a standards cat fight, defer's definition varies spec to spec, and even in the most recent specs doesn't offer a useful guarantee. As answers hereand this issuedemonstrate, browsers implement defer differently:
不幸的是,由于真正是标准的猫战,defer 的定义因规范而异,即使在最新的规范中也不能提供有用的保证。正如这里的答案和这个问题所展示的,浏览器以不同的方式实现 defer:
- In certain situations some browsers have a bug that causes
defer
scripts to run out of order. - Some browsers delay the
DOMContentLoaded
event until after thedefer
scripts have loaded, and some don't. - Some browsers obey
defer
on<script>
elements with inline code and without asrc
attribute, and some ignore it.
- 在某些情况下,某些浏览器存在导致
defer
脚本运行无序的错误。 - 一些浏览器将
DOMContentLoaded
事件延迟到defer
脚本加载之后,而有些则不会。 - 有些浏览器服从
defer
于<script>
与内嵌代码,并没有元素src
属性,有些忽略它。
Fortunately the spec does at least specify that async overrides defer. So you can treat all scripts as async and get a wide swath of browser support like so:
幸运的是,规范至少指定了异步覆盖延迟。因此,您可以将所有脚本视为异步并获得广泛的浏览器支持,如下所示:
<script defer async src="..."></script>
98% of browsers in use worldwide and 99% in the US will avoid blocking with this approach.
全球 98% 的浏览器和美国 99% 的浏览器将通过这种方法避免阻止。
(If you need to wait until the document has finished parsing, listen to the event DOMContentLoaded
event or use jQuery's handy .ready()
function. You'd want to do this anyway to fall back gracefully on browsers that don't implement defer
at all.)
(如果您需要等到文档完成解析,请监听事件DOMContentLoaded
事件或使用 jQuery 的便捷.ready()
功能。无论如何您都希望这样做,以便在根本没有实现的浏览器上优雅地回退defer
。)
回答by Rajesh Paul
defer
can only be used in <script>
tag for external scriptinclusion. Hence it is advised to be used in the <script>
-tags in the <head>
-section.
defer
只能在<script>
标记中用于外部脚本包含。因此,建议在<script>
-section 的 -tags 中使用<head>
。
回答by Bijoy Anupam
As defer attribute works only with scripts tag with src. Found a way to mimic defer for inline scripts. Use DOMContentLoaded event.
由于延迟属性仅适用于带有 src 的脚本标记。找到了一种模拟内联脚本 defer 的方法。使用 DOMContentLoaded 事件。
<script defer src="external-script.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
// Your inline scripts which uses methods from external-scripts.
});
</script>
This is because, DOMContentLoaded event fires after defer attributed scripts are completely loaded.
这是因为 DOMContentLoaded 事件在延迟属性脚本完全加载后触发。
回答by Soumitra
The defer attribute is only for external scripts (should only be used if the src attribute is present).
defer 属性仅用于外部脚本(仅当 src 属性存在时才应使用)。
回答by Maxim
Should be also noted that there might be problems in IE<=9 when using script defer
in certain situations. More on this: https://github.com/h5bp/lazyweb-requests/issues/42
还需要注意的是,script defer
在某些情况下使用IE<=9可能会出现问题。更多相关信息:https: //github.com/h5bp/lazyweb-requests/issues/42
回答by Flimm
Have a look at this excellent article Deep dive into the murky waters of script loadingby the Google developer Jake Archibald written in 2013.
看看这篇由 Google 开发人员 Jake Archibald 于 2013 年撰写的深入了解脚本加载的黑暗水域的优秀文章。
Quoting the relevant section from that article:
引用那篇文章的相关部分:
Defer
<script src="//other-domain.com/1.js" defer></script> <script src="2.js" defer></script>
Spec says: Download together, execute in order just before DOMContentLoaded. Ignore “defer” on scripts without “src”.
IE < 10 says: I might execute 2.js halfway through the execution of 1.js. Isn't that fun??
The browsers in redsay: I have no idea what this “defer” thing is, I'm going to load the scripts as if it weren't there.
Other browsers say: Ok, but I might not ignore “defer” on scripts without “src”.
推迟
<script src="//other-domain.com/1.js" defer></script> <script src="2.js" defer></script>
规范说:一起下载,在DOMContentLoaded之前按顺序执行。在没有“src”的脚本上忽略“defer”。
IE < 10 说:我可能会在执行 1.js 中途执行 2.js。那不是很好玩吗??
红色的浏览器说:我不知道这个“延迟”是什么,我要加载脚本,好像它不存在一样。
其他浏览器说:好的,但我可能不会忽略没有“src”的脚本上的“延迟”。
(I'll add that early versions of Firefox trigger DOMContentLoaded before the defer
scripts finish running, according to this comment.)
(根据此评论defer
,我将补充说,早期版本的 Firefox 会在脚本完成运行之前触发 DOMContentLoaded 。)
Modern browsers seem to support async
properly, but you need to be OK with scripts running out of order and possibly before DOMContentLoaded.
现代浏览器似乎可以async
正确支持,但是您需要对乱序运行的脚本以及可能在 DOMContentLoaded 之前运行的脚本感到满意。
回答by s-sharma
This Boolean attribute is set to indicate to a browser that the script is meant to be executed after the document has been parsed. Since this feature hasn't yet been implemented by all other major browsers, authors should not assume that the script's execution will actually be deferred. Never call document.write() from a defer script (since Gecko 1.9.2, this will blow away the document). The defer attribute shouldn't be used on scripts that don't have the src attribute. Since Gecko 1.9.2, the defer attribute is ignored on scripts that don't have the src attribute. However, in Gecko 1.9.1 even inline scripts are deferred if the defer attribute is set.
此布尔属性设置为向浏览器指示脚本将在文档被解析后执行。由于此功能尚未被所有其他主要浏览器实现,作者不应假设脚本的执行实际上会被推迟。永远不要从延迟脚本中调用 document.write()(从 Gecko 1.9.2 开始,这会破坏文档)。defer 属性不应用于没有 src 属性的脚本。从 Gecko 1.9.2 开始,没有 src 属性的脚本会忽略 defer 属性。但是,在 Gecko 1.9.1 中,如果设置了 defer 属性,甚至内联脚本也会被推迟。
deferworks with chrome , firefox , ie > 7 and Safari
defer适用于 chrome , firefox , 即 > 7 和 Safari
ref: https://developer.mozilla.org/en-US/docs/HTML/Element/script
参考:https: //developer.mozilla.org/en-US/docs/HTML/Element/script
回答by srikanth_k
The defer attribute is a boolean attribute.
defer 属性是一个布尔属性。
When present, it specifies that the script is executed when the page has finished parsing.
当存在时,它指定在页面完成解析时执行脚本。
Note: The defer attribute is only for external scripts (should only be used if the src attribute is present).
注意: defer 属性仅适用于外部脚本(仅当存在 src 属性时才应使用)。
Note: There are several ways an external script can be executed:
注意:有几种方法可以执行外部脚本:
If async is present: The script is executed asynchronously with the rest of the page (the script will be executed while the page continues the parsing) If async is not present and defer is present: The script is executed when the page has finished parsing If neither async or defer is present: The script is fetched and executed immediately, before the browser continues parsing the page
如果 async 存在:脚本与页面的其余部分异步执行(脚本将在页面继续解析时执行)如果 async 不存在且 defer 存在:当页面完成解析时执行脚本 If既不存在 async 也不存在 defer:在浏览器继续解析页面之前,立即获取并执行脚本