到底如何<script defer =“defer”>工作?

我有几个<script>元素,其中一些元素中的代码依赖于其他<script>元素中的代码。 我看到defer属性在这里可以派上用场,因为它允许代码块在执行中被推迟。

为了testing它,我在Chrome上执行了这个操作: http : //jsfiddle.net/xXZMN/ 。

 <script defer="defer">alert(2);</script> <script>alert(1)</script> <script defer="defer">alert(3);</script> 

但是,它警告2 - 1 - 3 。 为什么不提醒1 - 2 - 3

更新:2/19/2016

考虑这个答案过时了。 有关更新浏览器版本的信息,请参阅此post的其他解答。

================================================== =======

基本上,延迟告诉浏览器在执行脚本块中的JavaScript之前等待“准备就绪”。 通常这是在DOM完成加载和document.readyState == 4之后

延迟属性是特定于Internet Explorer。 在Internet Explorer 8中,在Windows 7上,我在JS Fiddletesting页面看到的结果是1 – 2 – 3。

结果可能因浏览器而异。

http://msdn.microsoft.com/en-us/library/ms533719(v=vs.85).aspx

与stream行的观点相反,IE比标准更经常地遵循标准,实际上在DOM Level 1 spec中定义了“defer”属性。http://www.w3.org/TR/REC-DOM-Level-1/level -酮中将Html.HTML

W3C的延期定义: http : //www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer :

“设置时,这个布尔属性向用户代理提供脚本不会生成任何文档内容的提示(例如,在javascript中没有”document.write“),因此用户代理可以继续parsing和呈现。

来自HTML5规范的几个片段: http : //w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async

如果src属性不存在,则不得指定延迟和asynchronous属性。


使用这些属性可以select三种可能的模式[asynchronous和延迟]。 如果存在async属性,那么只要脚本可用,脚本就会被asynchronous执行。 如果async属性不存在但是存在defer属性,那么脚本在页面parsing完成时执行。 如果两个属性都不存在,那么在用户代理继续parsing页面之前立即提取并执行脚本。


这些属性的确切处理细节,大多数历史原因,有些不平凡,涉及到HTML的许多方面。 因此实施要求必须分散在整个说明书中。 下面的algorithm(在本节中)描述了这个处理的核心,但是这些algorithm引用了HTML的脚本开始和结束标记的parsing规则,在外部内容和XML中,document.write ()方法,脚本处理等


如果元素具有src属性,并且元素具有defer属性,并且该元素已被标记为“parsing器插入的”,并且该元素没有async属性:

该元素必须添加到脚本列表的末尾,当文档完成与创build该元素的parsing器的Document相关联的parsing时将执行该脚本。

真正的答案是:因为你不能相信推迟。

在概念上,延迟和asynchronous的区别如下:

asynchronous允许脚本在后台下载而不被阻塞。 然后,下载完成的那一刻,呈现被阻止,脚本执行。 渲染脚本执行时恢复。

除了声明保证脚本按页面上指定的顺序执行以外, 延迟执行相同的操作,并且在文档完成分析后执行。 因此,一些脚本可能会完成下载,然后坐下来等待稍后下载但出现在脚本之前的脚本。

不幸的是,由于什么是真正的标准猫战,延迟的定义不同规范规范,即使在最新的规格不提供有用的保证。 在这里和这个问题的答案显示,浏览器实现延期不同:

  • 在某些情况下,某些浏览器有一个导致defer脚本不按顺序运行的错误。
  • 一些浏览器会延迟DOMContentLoaded事件,直到defer脚本加载完毕,有些则不会。
  • 有些浏览器服从defer使用内联代码并且没有src属性的<script>元素,有些浏览器忽略它。

幸运的是,规范至less指定了asynchronous覆盖延迟。 因此,您可以将所有脚本视为asynchronous,并获得如下所示的大量浏览器支持:

 <script defer async src="..."></script> 

98%的浏览器在全球使用,99%在美国使用这种方法将避免阻塞。

(如果你需要等到文档完成parsing,那么听取事件DOMContentLoaded事件或者使用jQuery的方便的.ready()函数,无论如何你都要这样做,以便在没有实现defer浏览器上优雅地回退所有。)

defer只能在<script>标签中用于外部脚本包含。 因此build议在<head><script>标签中使用。

defer属性仅用于外部脚本(只有在src属性存在的情况下才能使用)。

还应该注意的是,在某些情况下使用script defer时,IE <= 9时可能会出现问题。 更多关于这个: https : //github.com/h5bp/lazyweb-requests/issues/42

由于defer属性只适用于带有src的脚本标签。 find了一种模仿内联脚本延迟的方法。 使用DOMContentLoaded事件。

 <script defer src="external-script.js"></script> <script> document.addEventListener("DOMContentLoaded", function(event) { // Your inline scripts which uses methods from external-scripts. }); </script> 

这是因为,延迟属性脚本被完全加载后,DOMContentLoaded事件触发。

看看这篇优秀的文章深入探讨 Google开发人员Jake Archibald在2013年编写的脚本的黑暗水域 。

引用该条中的相关部分:

推迟

 <script src="//other-domain.com/1.js" defer></script> <script src="2.js" defer></script> 

Spec说 :一起下载,在DOMContentLoaded之前执行。 忽略没有“src”的脚本的“延迟”。

IE <10说 :我可能执行2.js执行1.js。 这不是很有趣吗?

红色的浏览器说 :我不知道这个“延迟”是什么,我要加载脚本,好像它不在那里。

其他浏览器说 :好的,但我可能不会忽略没有“src”的脚本“推迟”。

( 根据这个评论 ,我将在defer脚本运行之前添加Firefox的早期版本触发器DOMContentLoaded。)

现代浏览器似乎正确支持async ,但是您需要确保脚本运行不正常,可能在DOMContentLoaded之前运行。

这个布尔属性被设置为向浏览器指示该脚本将在文档被parsing之后被执行。 由于此function尚未被所有其他主stream浏览器实现,因此作者不应该假定脚本的执行实际上将被推迟。 永远不要从推迟脚本中调用document.write()(因为Gecko 1.9.2,这将会把文档吹走)。 defer属性不应该用于没有src属性的脚本。 由于Gecko 1.9.2,defer属性在没有src属性的脚本上被忽略。 但是,在Gecko 1.9.1中,如果设置了defer属性,那么即使内联脚本也被延迟。

延期工作与铬,Firefox,即> 7和Safari

ref: https : //developer.mozilla.org/en-US/docs/HTML/Element/script

defer属性是一个布尔属性。

当存在时,它指定脚本在页面parsing完成时执行。

注意:defer属性仅用于外部脚本(只有在src属性存在的情况下才能使用)。

注意:有几种方法可以执行外部脚本:

如果存在asynchronous:脚本与页面的其余部分asynchronous执行(当页面继续parsing时,脚本将被执行)如果async不存在并且存在延迟:脚本在页面完成parsing时执行If不存在asynchronous或延迟:在浏览器继续parsing页面之前,脚本被立即提取并执行

Interesting Posts