我对async
&属性有几个问题。 defer
标记的<script>
,据我所知,仅适用于HTML5浏览器。
我的一个网站有两个外部JavaScript文件,目前位于</body>
标记的上方;第一个是来自谷歌的jquery,第二个是本地外部脚本。
将async
添加到页面底部的两个脚本中是否有任何优势?
将async
选项添加到两个脚本并将它们放在<head>
页面的顶部是否有任何好处?
<script defer src=...
<head>
加载defer
内的两个脚本与使用</body>
之前的脚本具有相同的效果吗? <script async src=...
如果我有两个启用了async
的脚本
最后,我最好保留原样,直到HTML5更常用?
答案 0 :(得分:565)
此图片解释了正常的脚本标记,async和defer
一旦加载脚本就会执行异步脚本,所以它就会执行 不保证执行顺序(你包含的脚本) 结束可以在第一个脚本文件之前执行)
延迟脚本保证它们出现的执行顺序 在页面中。
参考此链接:http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html
答案 1 :(得分:334)
在</body>
之前保持您的脚本正确。在某些情况下,Async可以与位于那里的脚本一起使用(参见下面的讨论)。 Defer不会对位于那里的脚本产生太大影响,因为DOM解析工作已经完成了很多工作。
这篇文章解释了异步和延迟之间的区别:http://peter.sh/experiments/asynchronous-and-deferred-javascript-execution-explained/。
如果您在</body>
之前将脚本保留在正文末尾,那么您的HTML将在旧浏览器中更快地显示。因此,为了保持旧版浏览器的加载速度,您不希望将它们放在其他任何位置。
如果您的第二个脚本依赖于第一个脚本(例如,您的第二个脚本使用第一个脚本中加载的jQuery),那么您无法在没有其他代码来控制执行顺序的情况下使它们异步,但您可以让它们延迟,因为延迟脚本仍将按顺序执行,直到文档解析完毕为止。如果您拥有该代码并且不需要立即运行脚本,则可以使它们异步或延迟。
您可以将脚本放在<head>
标记中并将它们设置为defer
,并且将延迟加载脚本,直到解析DOM并在新浏览器中显示快速页面支持延迟,但它在旧版浏览器中根本不会帮助你,它实际上并不比仅在</body>
之前放置脚本在所有浏览器中都有效。所以,你可以看到为什么最好把它们放在</body>
之前。
当您在脚本加载时并不关心时,Async会更有用,并且用户所依赖的任何其他内容都不依赖于该脚本加载。最常被引用的使用异步的示例是像Google Analytics这样的分析脚本,您不需要等待任何事情,并且不急于即将运行并且它是独立的,因此没有其他任何依赖它。
通常jQuery库不适合async,因为其他脚本依赖它并且你想安装事件处理程序,所以你的页面可以开始响应用户事件,你可能需要运行一些基于jQuery的初始化代码来建立页面的初始状态。它可以用作异步,但是其他脚本必须编码才能在加载jQuery之前执行。
答案 2 :(得分:190)
HTML5:async
,defer
在HTML5中,您可以告诉浏览器何时运行JavaScript代码。有三种可能性:
<script src="myscript.js"></script>
<script async src="myscript.js"></script>
<script defer src="myscript.js"></script>
如果没有async
或defer
,浏览器会立即运行您的脚本,然后再渲染脚本标记下方的元素。
使用async
(异步),浏览器将继续加载HTML页面并在浏览器加载时呈现它并同时执行脚本。
使用defer
,浏览器将在页面完成解析后运行您的脚本。 (不必完成下载所有图像文件。这很好。)
答案 3 :(得分:23)
async
和defer
脚本都会立即开始下载,而不会暂停解析器,并且都支持可选的onload
处理程序,以满足执行初始化的常见需求,这取决于脚本。< / p>
async
和defer
之间的差异在于脚本执行时的中心。每个async
脚本在完成下载之后和窗口的加载事件之前的第一次机会执行。这意味着async
脚本可能(并且可能)不按页面中出现的顺序执行。而另一方面,defer
脚本保证按照它们在页面中出现的顺序执行。解析完成后,但在文档的DOMContentLoaded
事件之前,执行开始。
来源&amp;更多详情:here。
答案 4 :(得分:20)
面对同样的问题,现在清楚地了解两者是如何运作的。希望这个参考链接会有所帮助......
<强> 异步 强>
将async属性添加到脚本标记时,将发生以下情况。
<script src="myfile1.js" async></script>
<script src="myfile2.js" async></script>
<强> 推迟 强>
Defer非常类似于一个主要差异的异步。以下是浏览器遇到带有defer属性的脚本时发生的情况。
<script src="myfile1.js" defer></script>
<script src="myfile2.js" defer></script>
答案 5 :(得分:2)
我认为,杰克·阿奇博尔德(Jake Archibald)早在2013年就向我们提供了一些见解,这些见解可能会进一步增加对该主题的积极性:
https://www.html5rocks.com/en/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混淆,这从来都不是一件好事)。 / p>
上面的脚本应内联包含在页面的开头,请尽快对脚本下载进行排队,而不会破坏渐进式渲染,并应按指定的顺序尽快执行。 “ 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在评论中纠正了我。
答案 6 :(得分:0)
似乎延迟和异步的行为依赖于浏览器,至少在执行阶段。注意,延迟仅适用于外部脚本。我假设异步遵循相同的模式。
在IE 11及以下版本中,顺序似乎如下:
在Edge,Webkit等中,async属性似乎被忽略或放在最后:
在较新的浏览器中,data-pagespeed-no-defer属性在任何其他外部脚本之前运行。这适用于不依赖于DOM的脚本。
注意:当您需要明确执行外部脚本的顺序时,请使用延迟。这告诉浏览器按照放置在文件中的顺序执行所有延迟脚本。
ASIDE:外部javascripts的大小在加载时确实很重要......但对执行顺序没有影响。
如果您担心脚本的性能,可能需要考虑缩小或简单地使用XMLHttpRequest动态加载它们。
答案 7 :(得分:0)
渲染引擎经过几个步骤,直到它在屏幕上绘制任何东西。
看起来像这样:
同样的过程也适用于 CSS。 CSS 渲染引擎为 CSS 创建不同/分离的数据结构,但它被称为 CSSOM(CSS 对象模型)
浏览器仅适用于对象模型,因此它需要了解有关 DOM 和 CSSDOM 的所有信息。
下一步是以某种方式结合 DOM 和 CSSOM。因为没有 CSSOM 浏览器不知道如何在渲染过程中为每个元素设置样式。
以上所有信息意味着,您在 html(javascript、css)浏览器中提供的任何内容都将暂停 DOM 构建过程。如果您熟悉事件循环,那么事件循环如何执行任务有一个简单的规则:
因此,当您提供 Javascript 文件时,浏览器不知道 JS 代码将要做什么并停止所有 DOM 构建过程,而 Javascript 解释器开始解析和执行 Javascript 代码。
即使您在 body 标签的末尾提供 Javascript,浏览器也会对 HTML 和 CSS 进行上述所有步骤,但渲染除外。它会找出 Script 标签并停止直到 JS 完成。
但是 HTML 为脚本标记提供了两个额外的选项:async 和 defer。
异步 - 意味着在下载时执行代码,并且在下载过程中不阻塞 DOM 构建。
Defer - 表示在代码下载完成且浏览器完成 DOM 构建和渲染过程后执行代码。
答案 8 :(得分:0)
如果您的脚本不包含 DOM 操作并且其他脚本不依赖于此,则 Async 是合适的。 例如:bootstrap cdn,jquery
如果您的脚本包含 DOM 操作并且其他脚本依赖于此,则 Defer 是合适的。
例如:<script src=”createfirst.js”> //let this will create element <script src=”showfirst.js”> //after createfirst create element it will show that.
这样就可以了:
例如: <script defer src=”createfirst.js”> //let this will create element <script defer src=”showfirst.js”>
//after createfirst create element it will
这将按顺序执行脚本。
但是如果我做了:
例如: <script async src=”createfirst.js”> //let this will create element <script defer src=”showfirst.js”>
//after createfirst create element it will
然后,此代码可能会导致意外结果。 Coz:如果html解析器访问createfirst script。它不会停止DOM创建并开始从src下载代码。一旦src解析/代码下载,它将立即与DOM并行执行。
如果showfirst.js比createfirst.js先执行会怎样。如果createfirst需要很长时间(假设在DOM解析完成后),这可能是可能的。然后,showfirst会立即执行。
答案 9 :(得分:0)
答案 10 :(得分:-3)
async
和defer
将在HTML解析期间下载该文件。两者都不会中断解析器。
下载后,将执行具有async
属性的脚本。完成DOM解析后,将执行具有defer
属性的脚本。
加载async
的脚本不保证任何订单。加载defer
属性的脚本维护它们在DOM上的显示顺序。
当脚本不依赖任何内容时,请使用<script async>
。
当脚本依赖使用时。
最佳解决方案是在主体的底部添加。阻止或渲染没有问题。
<强>更新强>
答案已根据评论予以纠正。