脚本标签-异步和延迟


545

我有一对夫妇的有关属性的问题asyncdefer<script>标签,该标签在HTML5的浏览器我的理解只有工作。

我的一个网站有两个外部JavaScript文件,它们当前位于</body>标记上方;首先是 来自Google,第二个是本地外部脚本。

关于站点加载速度

  1. async在页面底部添加两个脚本是否有任何优势?

  2. async选项添加到两个脚本并将它们放在页面顶部的页面中,会有任何好处<head>吗?

  3. 这是否意味着它们会在页面加载时下载?
  4. 我认为这会导致HTML4浏览器出现延迟,但是会加快HTML5浏览器的页面加载速度吗?

使用 <script defer src=...

  1. <head>具有属性的两个脚本加载到内部是否 defer具有与之前拥有脚本相同的影响</body>
  2. 我再次假设这会使HTML4浏览器变慢。

使用 <script async src=...

如果我async启用了两个脚本

  1. 他们会同时下载吗?
  2. 还是一次与其余页面一起?
  3. 脚本的顺序是否会成为问题?例如,一个脚本依赖于另一个脚本,因此,如果一个脚本下载速度更快,则第二个脚本可能无法正确执行等。

最后,在HTML5更常用之前,我最好还是保持现状吗?


5
async是新的(ish),但defer自IE4以来已成为IE的一部分。defer是最近才被添加到其他浏览器中的,但是这些浏览器的旧版本往往会少得多。
Alohci 2012年

3
现在,HTML5变得非常流行!
2013年

2
defer与将脚本放置在HTML 底部相同,这已经很常见了很多年。
vsync

1
@vsync不一定正确,浏览器在解析脚本标签时将下载带有defer标签的JS,但是会将执行推迟到DOMContentLoaded之前。下载是非阻塞的。将HTML放置在HTML的底部将延迟JS的下载和执行,直到构建DOM为止,但是通过等待下载,您仍然会产生额外的延迟。
布拉德·弗罗斯特

@BradFrost-在我看来,下载受到了限制,从某种意义上说,这正在占用互联网带宽,对于那些连接速度较慢的用户,我认为必须首先加载该文档,然后在呈现该文档时才开始下载javascript文件。这是在情况如此,其中的内容是不是紧耦合的JavaScript渲染一切(如SPA
VSYNC

Answers:


404

保持脚本正确</body>。在某些情况下,异步可以与位于此处的脚本一起使用(请参见下面的讨论)。Defer不会对位于此处的脚本产生太大影响,因为DOM解析工作几乎已经完成。

这是一篇解释异步与延迟的区别的文章:http : //peter.sh/experiments/asynchronous-and-deferred-javascript-execution-explained/

如果您将脚本放在正文的末尾,那么在较旧的浏览器中,HTML的显示速度会更快</body>。因此,为了保持旧版浏览器的加载速度,您不想将它们放置在其他任何位置。

如果您的第二个脚本依赖于第一个脚本(例如,您的第二个脚本使用第一个脚本中加载的jQuery),那么如果没有其他代码来控制执行顺序,则无法使它们异步,但是可以使它们推迟,因为推迟脚本会仍然可以按顺序执行,只是直到文档被解析之后。如果您拥有该代码,并且不需要立即运行脚本,则可以使它们异步或延迟。

您可以将脚本放入<head>标记中并将其设置defer为,脚本的加载将推迟到DOM被解析之前,并且将在支持defer的新浏览器中快速显示页面,但对您完全没有帮助。在较旧的浏览器中,它并没有比</body>在所有浏览器中都可以正确使用脚本快得多。因此,您可以了解为什么最好将它们放在前面</body>

当您真的不在乎脚本何时加载,并且用户依赖的其他任何内容都不依赖于脚本加载时,异步更有用。引用次数最多的使用异步的示例是Google Analytics(分析)之类的分析脚本,您不需要等待任何东西,而且也不是迫切需要立即运行,而且它独立存在,因此没有其他依赖于此的脚本。

通常,jQuery库不是异步的理想选择,因为其他脚本依赖于它,并且您想安装事件处理程序,以便您的页面可以开始响应用户事件,并且您可能需要运行一些基于jQuery的初始化代码来建立初始状态页面的 可以异步使用它,但是必须对其他脚本进行编码才能在加载jQuery之前执行。


8
Defer应该按顺序运行它们,但是要在加载dom-content之前运行。这不是意味着将其放到首位会更快,因为它可以在对正文html进行解析之前开始下载它们?
凯文(Kevin)

9
您说过将脚本放入head并设置为defer不会比之前放任何脚本要快</body>,但是从我的理解来看,这是不正确的。考虑一下-如果将脚本放在中<head>,则它们将立即开始下载,而如果在此之前,</body>则所有其他元素都将首先下载。
Nate

12
@Nate-这不会使您的文档加载更快,这是我的观点。您是正确的,它可以改善更快地加载脚本的速度,但是也可能减慢文档及其内容的加载速度,因为您使用的是部分带宽,并且使用浏览器将与给定服务器建立的有限连接之一来在尝试加载内容的同时加载脚本。
jfriend00

4
“如果您的第二个脚本依赖于第一个脚本...那么您就不能使它们异步或延迟” –这是不正确的,因为延迟会按顺序执行。
DisgruntledGoat 2014年

2
从2012年发布此答案以来,对于浏览器开发而言,</ body>要求实际上并没有必要。
bgcode

839

此图说明了正常的脚本标记,异步和延迟

在此处输入图片说明

  • 异步脚本会在脚本加载后立即执行,因此不能保证执行顺序(最后包含的脚本可能会在第一个脚本文件之前执行)

  • 延迟脚本保证了它们在页面中出现的执行顺序。

引用此链接:http : //www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html


我认为使用多个脚本的示例会更好地说明其顺序
vsync

4
@writofmandamus看起来async会赢。见stackoverflow.com/questions/13821151/…–
Monsignor

感谢您的良好解释。但是,图像无法缩放。如果仅使用<script>标签,则页面加载的总长度要比下载脚本文件所花费的时间更长。
arni

@BhavikHirani根据此站点,如果浏览器支持在异步脚本中同时使用异步和延迟,则在浏览器支持异步的情况下使用异步;如果不支持异步,但支持延迟,则推迟使用延迟。行为是完全不同的,所以我不建议同时使用这两种行为,因为结果是不可预测的,并且可能是错误的重要来源。
阿德里安·维克

@arni仅在带宽很少被充分利用的情况下使用。而且,这两个下载将共享带宽,而不是共享带宽。—此外:这些图像显示为绿色解析,而不是下载。
罗伯·西默

212

HTML5 :asyncdefer

在HTML5中,您可以告诉浏览器何时运行JavaScript代码。有3种可能性:

<script       src="myscript.js"></script>

<script async src="myscript.js"></script>

<script defer src="myscript.js"></script>
  1. 不带asyncdefer,浏览器将在呈现script标记下方的元素之前立即运行您的脚本。

  2. 使用async(异步),浏览器将继续加载HTML页面并呈现它,而浏览器同时加载并执行脚本。

  3. 使用defer,页面解析完成后,浏览器将运行您的脚本。(不必完成所有图像文件的下载。这很好。)


async=""在验证并保存模板更改之前需要blogger.com模板。
noobninja 2015年

1
注意:不能保证脚本将按照使用异步指定的顺序运行。“因此,如果您的第二个脚本依赖于第一个脚本,请避免使用异步。”
Faisal Naseer '16

2
async-脚本执行的那一刻,他们已经下载的,没有考虑到他们在HTML文件中的顺序。
vsync

30

两者asyncdefer脚本都立即开始下载,而不会暂停解析器,并且两者都支持可选的onload处理程序,以解决执行依赖于脚本的初始化的常见需求。

之间的差异asyncdefer中心执行脚本时左右。每个async脚本在完成下载后以及窗口的加载事件之前都会首先执行。这意味着async脚本有可能(并且很可能)没有按照它们在页面中出现的顺序执行。尽管defer脚本,而另一方面,保证在它们出现在页面的顺序来执行。该执行在解析完全完成之后但在文档DOMContentLoaded事件之前开始。

来源和更多详细信息:此处


24

面对同样的问题,现在已经清楚地理解了两者的工作原理,希望该参考链接对您有所帮助...

异步

当您将async属性添加到脚本标签时,将发生以下情况。

<script src="myfile1.js" async></script>
<script src="myfile2.js" async></script>
  1. 发出并行请求以获取文件。
  2. 继续解析文档,就好像它从未中断过一样。
  3. 下载文件后立即执行各个脚本。

递延

Defer与异步非常相似,但有一个主要区别。当浏览器遇到带有defer属性的脚本时,将发生以下情况。

<script src="myfile1.js" defer></script>
<script src="myfile2.js" defer></script>
  1. 发出并行请求以获取单个文件。
  2. 继续解析文档,就好像它从未中断过一样。
  3. 即使脚本文件已下载,也要完成对文档的解析。
  4. 按照在文档中遇到的顺序执行每个脚本。

参考:异步和延迟之间的区别


7

async并将defer在HTML解析期间下载文件。两者都不会中断解析器。

  • 具有async属性的脚本将在下载后执行。虽然带有defer属性的脚本将在完成DOM解析后执行。

  • 加载的脚本async不保证任何顺序。当脚本加载了deferattribute时,它们会保持它们在DOM上的显示顺序。

使用<script async>时,脚本不依赖于任何东西。当脚本依赖使用时。

最好的解决方案是在主体底部添加。不会出现阻塞或渲染问题。


只是想在这里进行说明,这里发生了两件事。1.资源的下载2.资源的执行。在两种情况下(异步和延迟)资源的下载都不会被阻止,这意味着它们不会阻止html的解析,而在异步执行中会阻止解析,并且在延迟的情况下,执行会在html标记解析之后进行,因此在这种情况下不会阻塞。
pOoOf

5

我认为,杰克·阿奇博尔德(Jake Archibald)早在2013年就向我们提供了一些见解,这些见解可能会对该主题产生更大的积极性:

https://www.html5rocks.com/zh-CN/tutorials/speed/script-loading/

圣杯正在立即下载一组脚本,而不会阻止渲染,并按添加顺序尽快执行。不幸的是,HTML讨厌您,并且不允许您这样做。

(...)

答案实际上是在HTML5规范中,尽管它隐藏在脚本加载部分的底部。“ 异步IDL属性控制元素是否将异步执行。如果设置了元素的“ force-async”标志,则异步IDL属性在获取时必须返回true,在设置时必须返回“ force-async”必须首先取消设置标志... ”。

(...)

动态创建并添加到文档中的脚本默认情况下是异步的,它们不会阻止渲染并在下载后立即执行,这意味着它们可能以错误的顺序出现。但是,我们可以将它们明确标记为不异步:

[
    '//other-domain.com/1.js',
    '2.js'
].forEach(function(src) {
    var script = document.createElement('script');
    script.src = src;
    script.async = false;
    document.head.appendChild(script);
});

这使我们的脚本混合了普通HTML无法实现的行为。通过显式不异步,脚本被添加到执行队列中,与我们在第一个纯HTML示例中添加的脚本相同。但是,通过动态创建它们,它们可以在文档解析之外执行,因此在下载它们时不会阻止渲染(不要将非异步脚本加载与sync XHR混淆,这从来都不是一件好事)。

上面的脚本应内联包含在页面的开头,应尽快对脚本下载进行排队,而不会破坏渐进式渲染,并应按指定的顺序尽快执行。“ 2.js”可在“ 1.js”之前免费下载,但要等到“ 1.js”成功下载并执行或无法执行后才能执行。欢呼!异步下载但命令执行

不过,这可能不是加载脚本的最快方法:

(...)在上面的示例中,浏览器必须解析并执行脚本以发现要下载的脚本。这会将脚本隐藏在预加载扫描仪中。浏览器使用这些扫描仪在您可能下一步访问的页面上发现资源,或者在解析器被其他资源阻止时发现页面资源。

我们可以通过将其添加到文档的开头来重新添加可发现性:

<link rel="subresource" href="//other-domain.com/1.js">
<link rel="subresource" href="2.js">

这告诉浏览器页面需要1.js和2.js。link [rel = subresource]与link [rel = prefetch]类似,但语义不同。不幸的是,Chrome目前仅支持该脚本,您必须声明要加载两次的脚本,一次是通过链接元素,一次是在脚本中。

更正:我最初说这些是由预加载扫描仪拾取的,不是,而是由常规解析器拾取的。但是,预加载扫描程序可能无法进行预加载,而可执行代码中包含的脚本则永远无法预加载。感谢Yoav Weiss在评论中纠正了我。


1

似乎defer和async的行为至少在执行阶段取决于浏览器。注意,推迟仅适用于外部脚本。我假设异步遵循相同的模式。

在IE 11及以下版本中,顺序似乎是这样的:

  • 异步(在页面加载时可以部分执行)
  • 无(可以在页面加载时执行)
  • 延迟(在页面加载后执行,全部按文件中的放置顺序延迟)

在Edge,Webkit等中,async属性似乎被忽略或放置在末尾:

  • data-pagespeed-no-defer(在加载页面时,在执行任何其他脚本之前执行)
  • 无(可以在页面加载时执行)
  • 延迟(等到DOM加载后,全部按文件中的放置顺序延迟)
  • 异步(似乎要等到DOM加载完毕)

在较新的浏览器中,data-pagespeed-no-defer属性在任何其他外部脚本之前运行。这是针对不依赖DOM的脚本的。

注意:当需要外部脚本的明确执行顺序时,请使用defer。这告诉浏览器按照文件中的放置顺序执行所有延迟的脚本。

旁白:加载时外部javascript的大小确实很重要...但是对执行顺序没有影响。

如果您担心脚本的性能,则可能要考虑缩小或简单地使用XMLHttpRequest动态加载它们。


data-pagespeed-no-defer服务器端 PageSpeed模块使用的属性。该data-pagespeed-no-defer属性本身在任何浏览器中均无效。
Qtax
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.