javascript - 加载和执行脚本的顺序

标签 javascript load-order

在 html 页面中包含 JavaScript 的方法有很多种。我知道以下选项:

  • 内联代码或从外部 URI 加载
  • 包含在 或 标记中 [ 1 , 2 ]
  • 没有、deferasync 属性(仅限外部脚本)
  • 包含在静态源中或由其他脚本动态添加(在不同的解析状态下,使用不同的方法)

不计算硬盘中的浏览器脚本、javascript:URI 和 onEvent-attributes [ 3 ],已经有 16 种替代方法来执行 JS,但我确信我忘记了一些东西。

我不太关心快速(并行)加载,我更好奇执行顺序(这可能取决于加载顺序和 document order )。 是否有一个很好的(跨浏览器)引用涵盖了所有情况? http://www.websiteoptimization.com/speed/tweak/defer/只处理其中的 6 个,并且主要测试旧浏览器。

因为我担心没有,这是我的具体问题:我有一些用于初始化和脚本加载的(外部)头脚本。然后我在正文的末尾有两个静态的内联脚本。第一个让脚本加载器动态地将另一个脚本元素(引用外部 js)附加到主体。第二个静态内联脚本想要使用添加的外部脚本中的 js。它可以依赖于另一个已被执行的(以及为什么:-)?

最佳答案

如果您没有动态加载脚本或将它们标记为 deferasync ,然后脚本按照页面中遇到的顺序加载。无论是外部脚本还是内联脚本都没有关系 - 它们按照在页面中遇到的顺序执行。外部脚本之后的内联脚本将被保留,直到它们之前的所有外部脚本加载并运行为止。

异步脚本(无论它们如何指定为异步)以不可预测的顺序加载和运行。浏览器并行加载它们,并且可以按照它想要的任何顺序运行它们。

多个异步事物之间没有可预测的顺序。如果需要一种可预测的顺序,则必须通过注册来自异步脚本的加载通知并在加载适当的内容时手动排序 javascript 调用来进行编码。

动态插入脚本标签时,执行顺序的行为方式将取决于浏览器。您可以在 this reference article 中查看 Firefox 的行为方式。 。简而言之,较新版本的 Firefox 默认将动态添加的脚本标签设置为异步,除非脚本标签已另外设置。

带有async的脚本标签可以在加载后立即运行。事实上,浏览器可能会暂停解析器正在执行的任何操作并运行该脚本。所以,它确实可以几乎随时运行。如果脚本被缓存,它可能几乎立即运行。如果脚本需要一段时间才能加载,它可能会在解析器完成后运行。要记住的一件事是 async是它可以随时运行,而且时间是不可预测的。

带有defer的脚本标签等待整个解析器完成,然后运行所有标有 defer 的脚本按照他们遇到的顺序。这允许您将多个相互依赖的脚本标记为 defer 。它们都将被推迟到文档解析器完成之后,但它们将按照遇到的顺序执行,保留它们的依赖关系。我想到defer就像脚本被放入队列中一样,解析器完成后将对其进行处理。从技术上讲,浏览器可能随时在后台下载脚本,但它们不会执行或阻止解析器,直到解析器完成解析页面并解析并运行任何未标记 defer 的内联脚本。或async .

以下是该文章的引用:

script-inserted scripts execute asynchronously in IE and WebKit, but synchronously in Opera and pre-4.0 Firefox.

HTML5 规范的相关部分(对于较新的兼容浏览器)是 here 。其中有很多关于异步行为的内容。显然,此规范不适用于较旧的浏览器(或不合规的浏览器),您可能必须测试其行为才能确定。

引用 HTML5 规范:

Then, the first of the following options that describes the situation must be followed:

If the element has a src attribute, and the element has a defer attribute, and the element has been flagged as "parser-inserted", and the element does not have an async attribute The element must be added to the end of the list of scripts that will execute when the document has finished parsing associated with the Document of the parser that created the element.

The task that the networking task source places on the task queue once the fetching algorithm has completed must set the element's "ready to be parser-executed" flag. The parser will handle executing the script.

If the element has a src attribute, and the element has been flagged as "parser-inserted", and the element does not have an async attribute The element is the pending parsing-blocking script of the Document of the parser that created the element. (There can only be one such script per Document at a time.)

The task that the networking task source places on the task queue once the fetching algorithm has completed must set the element's "ready to be parser-executed" flag. The parser will handle executing the script.

If the element does not have a src attribute, and the element has been flagged as "parser-inserted", and the Document of the HTML parser or XML parser that created the script element has a style sheet that is blocking scripts The element is the pending parsing-blocking script of the Document of the parser that created the element. (There can only be one such script per Document at a time.)

Set the element's "ready to be parser-executed" flag. The parser will handle executing the script.

If the element has a src attribute, does not have an async attribute, and does not have the "force-async" flag set The element must be added to the end of the list of scripts that will execute in order as soon as possible associated with the Document of the script element at the time the prepare a script algorithm started.

The task that the networking task source places on the task queue once the fetching algorithm has completed must run the following steps:

If the element is not now the first element in the list of scripts that will execute in order as soon as possible to which it was added above, then mark the element as ready but abort these steps without executing the script yet.

Execution: Execute the script block corresponding to the first script element in this list of scripts that will execute in order as soon as possible.

Remove the first element from this list of scripts that will execute in order as soon as possible.

If this list of scripts that will execute in order as soon as possible is still not empty and the first entry has already been marked as ready, then jump back to the step labeled execution.

If the element has a src attribute The element must be added to the set of scripts that will execute as soon as possible of the Document of the script element at the time the prepare a script algorithm started.

The task that the networking task source places on the task queue once the fetching algorithm has completed must execute the script block and then remove the element from the set of scripts that will execute as soon as possible.

Otherwise The user agent must immediately execute the script block, even if other scripts are already executing.

<小时/>

Javascript 模块脚本怎么样,type="module"

Javascript 现在支持使用如下语法加载模块:

<script type="module">
  import {addTextToBody} from './utils.mjs';

  addTextToBody('Modules are pretty cool.');
</script>

或者,与 src属性:

<script type="module" src="http://somedomain.com/somescript.mjs">
</script>

所有带有 type="module" 的脚本自动给出 defer属性。这会与页面的其他加载并行(如果不是内联)下载它们,然后按顺序运行它们,但在解析器完成之后。

模块脚本也可以指定为 async属性将尽快运行内联模块脚本,不等待解析器完成,也不等待运行 async相对于其他脚本以任何特定顺序编写的脚本。

有一个非常有用的时间线图表,显示了不同脚本组合的获取和执行,包括本文中的模块脚本:Javascript Module Loading .

关于javascript - 加载和执行脚本的顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8996852/

相关文章:

java - 获取 jUnit :s @BeforeClass 的静态字段

javascript - 扩展 V8 JavaScript 引擎

javascript - 构建失败 'Blob' : Array length exceeds supported limit

javascript - 在元素加载到 DOM 之前添加元素加载事件

javascript - 以松散模式将 ES6 编译为 ES5 构造函数

ruby-on-rails - 如何在 gem 中扩展 ApplicationController?

javascript - css/js 中的自动换行

javascript - html页面加载后加载javascript

css - Meteor Bootstrap 节点模块覆盖我自己的 css