题 如果脚本动态添加到DOM,“async”属性/属性是否有用?


这个问题有点像 哪些浏览器支持<script async =“async”/>?

我最近看过一些脚本做的事情是这样的:

var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = 'http://www.example.com/script.js';
document.getElementsByTagName('head')[0].appendChild(s);

这是一种动态地向DOM添加脚本的常用方法,来自Steve Souders的书中的IIRC“甚至更快的网站,“提示所有现代浏览器异步加载脚本(即,不阻止页面呈现或下载后续资产)。

如果我是正确的,那么 s.async = true 声明有什么用?即使对于支持该属性的浏览器,它也不会是多余的,因为动态附加脚本应该已经触发异步下载吗?


30
2017-08-04 18:52


起源




答案:


答案在撰写本文时已被接受 已过期。该 规范 现在决定了 script 元素  解析器插入是异步;该 async property与非解析器插入无关 script 内容:

第三个是一个标志,表明该元素是否“力异步“。 原来, script 元素必须设置此标志。 HTML解析器和XML解析器没有设置它 script 他们插入的元素。另外,每当一个脚本元素的“力异步“旗帜设置有一个 async 添加了内容属性,元素的“力异步“国旗必须取消。

有了 async 当然,content属性确实意味着脚本将异步执行。规范语言 似乎 留下机会强制同步执行脚本(通过设置属性,然后删除它),但在实践中,这不起作用,可能只是在规范中有点模糊。非解析器插入 script 元素是异步的。

这个指定的行为是IE和Chrome一直以来所做的,Firefox已经做了多年,而且当前Opera也做了(我不知道它何时从上面链接的答案中的旧行为改变)。

它很容易测试:

var script = document.createElement("script");
script.src = "script.js";
console.log("a");
document.body.appendChild(script);
console.log("b");

...用 script.js 存在

console.log("script loaded");

......会记录

一个
b
脚本已加载

10
2018-04-14 14:18



谢谢。这应该是公认的答案,因为目前接受的答案已经过时。 - jhuesos


问题是 s.async = true 可用于动态插入的脚本,或者这些脚本已经异步加载。答案是他们  如上所述,在所有浏览器中异步加载 这里 (感谢Markus Olsson的链接)

脚本插入的脚本在IE和WebKit中异步执行,但在Opera和4.0之前的Firefox中同步执行。在Firefox 4.0中,对于脚本创建的脚本,async DOM属性默认为true,因此默认行为与IE和WebKit的行为相匹配。

在支持的浏览器中 async 但是还没有默认异步加载(例如,Firefox 3.6), async = true 有所作为。

(上面的链接确认了Gecko 1.9.2支持async,这是Firefox 3.6使用的布局引擎)


20
2018-03-01 21:37



关于最近的浏览器版本的答案更新会很有趣。我目前正在使用 s.setAttribute("async", "");。你知道这是否有效? - Gruber
是否有一个徽章“6年后回来接受一直都是正确的答案,同时导致新接受的答案自相矛盾,因为它将接受的答案称为错误,当它刚刚成为正确答案时本身?” - Bungle


有趣 - 我认为事实证明我的假设是错误的。

基于jQuery开发人员论坛中的这个主题:

http://forum.jquery.com/topic/jquery-ajax-async-vs-html5-script-async

它看起来像 async 已发现属性对动态附加脚本有影响,至少在Firefox中(可能是Opera,但它还不支持该属性)。

论坛帖子还引用了谷歌的异步跟踪代码实现,虽然它似乎利用了 async 在适当的上下文中,属性实际上似乎得到了错误的语法。 Google使用:

ga.async = true;

当显然不起作用;正确的方法是使用:

ga.async = 'async';

要么

ga.setAttribute('async', 'async');

因此,根据我目前的理解,并非所有浏览器在所有情况下都会在插入DOM后立即执行动态附加脚本; Firefox(最终是Opera)将需要 async 要设置的属性以确保始终发生这种情况。

关于Firefox的实现的更多信息 async 这里:

https://bugzilla.mozilla.org/show_bug.cgi?id=503481


2
2017-08-10 03:47



在jQuery论坛上非常有趣的线索。猜猜我的google fu不够强大,无法找到它;)谢谢! - Markus Olsson
我不认为这是正确的。 typeof ga.async 是 "boolean",甚至在你设置之后 'async' 你会发现ga.async的值为 true (由于类型强制)。我在FF 3.6中检查过这个 - Tim Goodman
我相信那个说它没有在jQuery中运行的人误解了async属性应该做什么,正如其他一些海报所指出的那样。顺便说一句,请注意 ga.async = true 得到HTML的结果 <script type="text/javascript" src="foo.js" async=""> (至少在Firebug中看到的)但据我所知,重要的是async属性的存在,而不是跟随它的字符串。无论如何, ga.async = "async"导致同样的事情。 - Tim Goodman
纠正我的最后评论,显然是 async 属性被赋予一个值 在标记中 它应该是“异步”或空字符串。但是在设置时 在DOM中 (如 ga.async =)async是一个布尔值,所以你应该将它设置为 true 要么 false。正如我所说,事实 ga.async = "async" 产生相同的结果只是因为 "async" 是被胁迫的 true。 - Tim Goodman


我相信你是对的。

史蒂夫自己的例子 在将脚本标记附加到head元素之前,他没有设置async属性。

我的理解了 异步atttribute 这是一种通过使用document.write向浏览器发信号通知您不打算操纵页面的方式,以便它可以继续呈现而不是停止加载脚本。请参阅文档 mdc的脚本元素 其中包含有关document.write / async问题的更多信息。

请注意,使用您的技术,您无论如何都不应该使用document.write,因为您无法知道脚本在页面生命周期中的加载位置。


1
2017-08-05 01:14



马库斯 - 很棒的答案,我感谢你的贡献!我进一步研究了这一点,并做了一些发现 - 请阅读我刚刚补充的答案。 - Bungle