在 html 页面中包含 JavaScript 有很多不同的方法。我知道以下选项:
不计算来自硬盘的浏览器脚本、javascript:URIs 和 onEvent
-attributes [ 3 ],已经有 16 种替代方法可以让 JS 执行,我确定我忘记了一些东西。
我不太关心快速(并行)加载,我对执行顺序更好奇(这可能取决于加载顺序和 文档顺序)。 是否有 涵盖所有情况的良好(跨浏览器)参考? 例如 http://www.websiteoptimization.com/speed/tweak/defer/ 只处理其中的 6 个,并且主要测试旧浏览器。
我担心没有,这是我的具体问题:我有一些(外部)头脚本用于初始化和脚本加载。然后我在正文的末尾有两个静态的内联脚本。第一个允许脚本加载器动态地将另一个脚本元素(引用外部 js)附加到正文。第二个静态内联脚本想要使用添加的外部脚本中的 js。它可以依赖于另一个已被执行(以及为什么:-)?
原文由 Bergi 发布,翻译遵循 CC BY-SA 4.0 许可协议
如果您没有动态加载脚本或将它们标记为
defer
或async
,则脚本将按照页面中遇到的顺序加载。无论是外部脚本还是内联脚本都没有关系 - 它们按照在页面中遇到的顺序执行。外部脚本之后的内联脚本会一直保留,直到它们之前的所有外部脚本都已加载并运行。异步脚本(无论它们如何指定为异步)以不可预知的顺序加载和运行。浏览器并行加载它们,并且可以按照它想要的任何顺序自由运行它们。
多个异步事物之间没有可预测的顺序。如果需要一个可预测的顺序,则必须通过注册来自异步脚本的加载通知并在加载适当的内容时手动排序 javascript 调用来对其进行编码。
当动态插入脚本标签时,执行顺序的行为将取决于浏览器。您可以在 这篇参考文章 中了解 Firefox 的行为方式。简而言之,新版本的 Firefox 默认将动态添加的脚本标签设置为异步,除非另外设置了脚本标签。
带有
async
的脚本标签可以在加载后立即运行。实际上,浏览器可能会暂停解析器正在执行的任何其他操作并运行该脚本。因此,它几乎可以随时运行。如果脚本被缓存,它可能几乎立即运行。如果脚本需要一段时间才能加载,它可能会在解析器完成后运行。使用async
要记住的一件事是它可以随时运行,而且时间是不可预测的。带有
defer
的脚本标签会等待整个解析器完成,然后按照遇到的顺序运行所有带有defer
标记的脚本。这允许您将多个相互依赖的脚本标记为defer
。它们都将被推迟到文档解析器完成之后,但它们将按照遇到的顺序执行,保留它们的依赖关系。我认为defer
就像脚本被放入将在解析器完成后处理的队列中一样。从技术上讲,浏览器可能随时在后台下载脚本,但在解析器完成页面解析并解析和运行任何未标记为defer
或async
的内联脚本之前,它们不会执行或阻止解析器。这是那篇文章的引述:
HTML5 规范(适用于较新的兼容浏览器)的相关部分在 此处。那里有很多关于异步行为的文章。显然,此规范不适用于您可能需要测试才能确定其行为的旧浏览器(或不符合标准的浏览器)。
引用 HTML5 规范:
Javascript 模块脚本
type="module"
怎么样?Javascript 现在支持使用如下语法加载模块:
或者,使用
src
属性:所有
type="module"
的脚本都会自动赋予defer
属性。这将与页面的其他加载并行(如果不是内联)下载它们,然后按顺序运行它们,但在解析器完成之后。模块脚本也可以被赋予
async
属性,它将尽快运行内联模块脚本,而不是等到解析器完成并且不等待以相对于其他脚本的任何特定顺序运行async
脚本。有一个非常有用的时间线图,显示了不同脚本组合的获取和执行,包括本文中的模块脚本: Javascript 模块加载。