【问题标题】:Is the "async" attribute/property useful if a script is dynamically added to the DOM?如果将脚本动态添加到 DOM,“异步”属性/属性是否有用?
【发布时间】:2011-03-25 10:35:13
【问题描述】:

这个问题有点像Which browsers support <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 的书“Even Faster Web Sites”中的 IIRC 提示所有现代浏览器异步加载脚本(即,不阻止页面呈现或下载后续资产)。

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

【问题讨论】:

    标签: javascript asynchronous pageload page-load-time


    【解决方案1】:

    问题是s.async = true 是否对动态插入的脚本有用,或者这些脚本是否已经异步加载。答案是它们不是在所有浏览器中异步加载,正如here 解释的那样(感谢 Markus Olsson 提供的链接)

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

    在支持 async 但尚未默认异步加载的浏览器中(例如 Firefox 3.6),async = true 会有所不同。

    (上面的链接确认 Gecko 1.9.2 支持异步,Firefox 3.6 使用的布局引擎)

    【讨论】:

    • 对有关最新浏览器版本的答案更新会很有趣。我目前使用s.setAttribute("async", "");。你知道这是否有效吗?
    • 是否有“6年后回来接受一个一直正确的答案,同时导致新接受的答案自相矛盾,因为它指的是接受的答案是错误的,当它本身成为正确答案时?”
    【解决方案2】:

    specification(现在)指示解析器插入的script 元素是异步的; async 属性与非解析器插入的 script 元素无关:

    第三个是指示元素是否会“force-async”的标志。最初,script 元素必须设置此标志。 HTML 解析器和 XML 解析器在它们插入的 script 元素上取消设置它。此外,只要设置了“force-async”标志的脚本元素添加了async 内容属性,则必须取消设置元素的“force-async”标志.

    拥有async 内容属性当然意味着脚本将异步执行。规范语言似乎留下了强制同步执行脚本的机会(通过设置属性然后删除它),但在实践中这不起作用并且可能只是在规格。非解析器插入的 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 已加载脚本

    【讨论】:

      【解决方案3】:

      有趣 - 我认为我的假设是错误的。

      基于 jQuery 开发者论坛中的这个帖子:

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

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

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

      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

      【讨论】:

      • jQuery 论坛上非常有趣的话题。猜猜我的 google fu 不够强大,无法找到它;)谢谢!
      • 我不认为这是正确的。 typeof ga.async"boolean",即使将其设置为 'async',您也会发现 ga.async 的值为 true(由于类型强制)。我在 FF 3.6 中检查了这个
      • 我相信说它在 jQuery 中不起作用的人误解了 async 属性应该做什么,正如其他一些海报所指出的那样。顺便说一句,请注意ga.async = true 会产生类似于&lt;script type="text/javascript" src="foo.js" async=""&gt; 的HTML(至少在Firebug 中是这样),但据我所知,重要的是async 属性的存在,而不是它后面的字符串。无论如何,ga.async = "async" 的结果是一样的。
      • 纠正我的最后一条评论,显然如果async 属性在标记中被赋予一个值,它应该是“异步”或空字符串。但是当 在 DOM 中 设置它时(如在ga.async = 中),异步是一个布尔值,所以你应该将它设置为truefalse。正如我所说,ga.async = "async" 产生相同结果的事实只是因为"async" 被强制转换为true
      【解决方案4】:

      我相信你是对的。

      Steve's own examples 中,他在将 script 标签附加到 head 元素之前没有设置 async 属性。

      我对@9​​87654322@ 的理解是,它是一种向浏览器发出信号的方式,即您不打算通过使用 document.write 来操作页面,以便它可以继续呈现而不是停止加载脚本。请参阅script element at mdc 的文档,其中包含有关 document.write/async 问题的更多信息。

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

      【讨论】:

      • Markus - 很好的回答,感谢您的贡献!我对此进行了进一步调查,并做出了一些发现 - 请阅读我刚刚添加的答案。
      猜你喜欢
      • 1970-01-01
      • 2020-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-28
      相关资源
      最近更新 更多