脚本标记 - 异步和延迟

Ada*_*dam 460 javascript html5

我对标签的属性async和标签有几个问题,据我所知,只能在HTML5浏览器中使用.defer<script>

我的一个网站有两个外部JavaScript文件,目前位于</body>标签上方; 第一个是来自谷歌的,第二个是本地外部脚本.

关于网站加载速度

  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更常用?

Pra*_*dra 695

此图像解释了正常的脚本标记,异步和延迟

在此输入图像描述

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

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

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

  • 感谢您的良好解释。然而,这些图像并非按比例绘制。如果只有“&lt;script&gt;”标记,则下载脚本文件所需的时间会导致页面加载的总长度更长。 (13认同)
  • 我希望他们允许`defer`用于内联脚本(即非``src =""`脚本),以避免需要在`window.addEventListener('DOMContentLoaded,handler)`回调中包装所有内容. (9认同)
  • 所以在这个例子中不会``<script defer>`和`<script async defer>产生相同的结果? (8认同)
  • 我认为具有多个脚本的示例会更好地说明它们的顺序 (6认同)
  • @writofmandamus看起来`async`会赢。参见/sf/ask/967480601/ (3认同)
  • 这确实帮助我更好地理解了。 (2认同)

jfr*_*d00 368

保持您的脚本正确</body>.在某些情况下,Async可以与位于那里的脚本一起使用(参见下面的讨论).Defer不会对位于那里的脚本产生很大的影响,因为DOM解析工作已经完成了很多工作.

这篇文章解释了异步和延迟之间的区别:http://peter.sh/experiments/asynchronous-and-deferred-javascript-execution-explained/.

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

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

您可以将脚本放在<head>标记中并将其设置为,defer并且脚本的加载将推迟到解析DOM并且将在支持延迟的新浏览器中快速显示页面,但它根本无法帮助您在较旧的浏览器中,它并不比仅仅在</body>适用于所有浏览器的脚本之前更快.所以,你可以看出为什么最好把它们放在前面</body>.

当您在脚本加载时并不关心时,Async会更有用,并且用户所依赖的任何其他内容都不依赖于该脚本加载.最常被引用的使用异步的示例是像Google Analytics这样的分析脚本,您不需要等待任何事情,并且不急于即将运行并且它是独立的,因此没有其他任何依赖它.

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

  • @Nate - 它不会使你的文档加载更快,这是我的观点.你是正确的,它可以更快地改进加载脚本,但它也可能减慢文档及其内容的加载速度,因为你正在使用一些带宽并使用浏览器将对给定服务器进行的有限连接之一在脚本尝试加载内容时加载脚本. (10认同)
  • 你说把脚本放在`head`中并将它们设置为`defer`并不比把它们放在`</ body>`之前快,但是从我读过的那些不正确.想想看 - 如果你把脚本放在`<head>`中,那么它们会立即开始下载,而如果它们在`</ body>`之前,那么所有其他元素首先下载. (8认同)
  • Defer应该按顺序运行它们,但是在dom-contentloaded之前运行.这不意味着把它放在头脑中会更快,因为它可以在解析主体html之前开始下载它们吗? (6认同)
  • "如果你的第二个脚本依赖于第一个脚本......那么你就不能让它们异步或延迟" - 这不是真的,推迟它们按顺序执行. (4认同)
  • 在这一点上,自 2012 年发布此答案以来,浏览器开发实际上并不需要 &lt;/body&gt; 要求。 (3认同)

小智 200

HTML5 : async,defer

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

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

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

<script defer src="myscript.js"></script>
Run Code Online (Sandbox Code Playgroud)
  1. 如果没有asyncdefer,浏览器将立即运行您的脚本,然后再渲染脚本标记下方的元素.

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

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

  • 注意:不能保证脚本将按照使用异步指定的顺序运行。“因此,如果您的第二个脚本依赖于第一个脚本,请避免异步。” (2认同)
  • `async`-脚本在被下载的瞬间执行,而不考虑它们在HTML文件中的顺序。 (2认同)

Zam*_*han 28

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

脚本执行时的区别asyncdefer中心.每个async脚本在完成下载之后和窗口加载事件之前的第一个机会执行.这意味着async脚本可能(并且可能)不按页面中出现的顺序执行.而另一方面,defer脚本保证按照它们在页面中出现的顺序执行.解析完成后,但在文档DOMContentLoaded事件之前,执行开始.

来源及进一步细节:这里.


kam*_*esh 24

面对同样的问题,现在清楚地了解两者是如何工作的.希望这个参考链接会有所帮助......

异步

将async属性添加到脚本标记时,将发生以下情况.

<script src="myfile1.js" async></script>
<script src="myfile2.js" async></script>
Run Code Online (Sandbox Code Playgroud)
  1. 进行并行请求以获取文件.
  2. 继续解析文档,好像它从未被中断过一样.
  3. 下载文件时执行各个脚本.

推迟

Defer非常类似于一个主要差异的异步.以下是浏览器遇到带有defer属性的脚本时发生的情况.

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

参考:Async和Defer之间的区别


Sup*_*del 20

好的做法是将所有文件保留在源文件夹中,以快速加载源文件。您需要下载所有脚本、样式、图标和图像相关文件,并将这些文件放入您的项目文件夹中。

在项目中创建这些文件夹来保存不同的源文件,然后将所需的文件从这些文件夹加载到页面中。

js:保存脚本相关文件。

css:保存与样式相关的文件。

images:保存图像/图标相关文件

fonts:保存字体相关文件


何时使用defer以及标签async上的属性<script>

deferattribute:首先deferattribute会下载脚本文件,然后等待HTML解析。HTML解析结束后,脚本将被执行。换句话说,它将保证所有脚本在 HTML 解析后都会执行。

defer当脚本用于 DOM 操作时,该属性非常有用。

asyncattribute:async属性会下载脚本文件并执行,无需等待HTML解析结束。换句话说,它不保证所有脚本在 HTML 解析后都会执行。

async当脚本不用于 DOM 操作时,该属性非常有用。有时,您只需要一个脚本来进行服务器端操作或处理缓存或 cookie,而不需要进行 DOM 操作。

在此输入图像描述


何时使用 defer 和 async 的有用链接: /sf/answers/4825048931/


小智 18

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

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

  • 加载的脚本async不保证任何顺序。虽然加载了defer属性的脚本保持了它们在 DOM 上出现的顺序。

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

最好的解决方案是<script>在身体的底部添加。阻塞或渲染不会有问题。


mjf*_*eto 5

我认为 Jake Archibald 早在 2013 年就向我们提供了一些见解,这些见解可能会为该主题增添更多积极性:

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

圣杯是在不阻塞渲染的情况下立即下载一组脚本,并按照添加顺序尽快执行。不幸的是,HTML 讨厌你,不会让你这样做。

(……)

答案实际上在 HTML5 规范中,尽管它隐藏在脚本加载部分的底部。" async IDL 属性控制元素是否异步执行。如果设置了元素的“force-async”标志,则在获取时,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);
});
Run Code Online (Sandbox Code Playgroud)

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

上面的脚本应该内嵌在页面的头部,在不中断渐进式渲染的情况下尽快排队脚本下载,并按照您指定的顺序尽快执行。“2.js”可以在“1.js”之前免费下载,但是直到“1.js”成功下载并执行或失败后才会执行。欢呼!异步下载但有序执行

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

(...) 对于上面的示例,浏览器必须解析并执行脚本以发现要下载的脚本。这会向预加载扫描程序隐藏您的脚本。浏览器使用这些扫描器来发现您接下来可能访问的页面上的资源,或者在解析器被另一个资源阻止时发现页面资源。

我们可以通过把它放在文档的头部来增加可发现性:

<link rel="subresource" href="//other-domain.com/1.js">
<link rel="subresource" href="2.js">
Run Code Online (Sandbox Code Playgroud)

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

更正:我最初说这些是由预加载扫描器拾取的,它们不是,它们是由常规解析器拾取的。然而,预加载扫描器可以选择这些,只是还没有,而可执行代码包含的脚本永远不能被预加载。感谢 Yoav Weiss 在评论中纠正了我。