当前位置: 首页 > 面试题库 >

加载和执行脚本顺序

郎诚
2023-03-14
问题内容

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

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

不计算硬盘中的浏览器脚本,javascript:URI和onEvent-attributes [[3]
],已经有16种方法可以使JS执行,我敢肯定我忘了一些东西。

我不太关心快速(并行)加载,我对执行顺序(可能取决于加载顺序和[文档顺序])更好奇。
是否有一个 涵盖所有情况 的良好 (跨浏览器) 参考?

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


问题答案:

如果您不是动态加载脚本或将其标记为deferasync,那么将按照页面中遇到的顺序加载脚本。不管是外部脚本还是内联脚本,它们都按照在页面中遇到的顺序执行。保留外部脚本之后的内联脚本,直到加载并运行之前的所有外部脚本为止。

异步脚本(无论如何将其指定为异步脚本)均以不可预测的顺序加载和运行。浏览器以并行方式加载它们,并且可以按任意顺序自由运行它们。

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

动态插入脚本标签时,执行顺序的行为取决于浏览器。您可以在本参考文章中了解Firefox的行为。简而言之,较新版本的Firefox会将动态添加的脚本标签默认为异步,除非另行设置了脚本标签。

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

带有脚本标记的脚本defer会等到整个解析器完成后,再按defer遇到的顺序运行所有标有的脚本。这样,您就可以将几个相互依赖的脚本标记为defer。它们都会被推迟到文档解析器完成之后,但是它们将按照遇到的顺序执行,并保留了它们的依赖关系。我认为defer脚本已放入解析器完成处理的队列中。从技术上讲,浏览器可能会随时在后台下载脚本,但是直到解析器解析完页面并解析并运行任何未标记defer或的内联脚本之后,它们才会执行或阻止解析器async

这是该文章的引文:

插入脚本的脚本在IE和WebKit中异步执行,但是在Opera和4.0之前的Firefox中同步执行。

HTML5规范的相关部分(适用于较新的兼容浏览器)在此处。那里写了很多有关异步行为的内容。显然,此规范不适用于您可能必须测试以确定其行为的旧版浏览器(或格式不正确的浏览器)。

HTML5规范的引文:

然后,必须遵循以下描述情况的第一个选项:

如果该元素具有src属性,并且该元素具有defer属性,并且该元素已被标记为“插入分析器”,并且该元素没有异步属性,则
该元素必须添加到列表的末尾与创建元素的解析器的Document相关联的文档完成解析后将执行的脚本。

一旦获取算法完成,联网任务源将其放置在任务队列上的任务必须设置元素的“准备由解析器执行”标志。解析器将处理执行脚本。

如果该元素具有src属性,并且该元素已被标记为“插入分析器”,并且该元素没有异步属性,则
该元素是创建该元素的分析器的文档的待处理分析阻止脚本。(每个文档一次只能有一个这样的脚本。)

一旦获取算法完成,联网任务源将其放置在任务队列上的任务必须设置元素的“准备由解析器执行”标志。解析器将处理执行脚本。

如果该元素不具有src属性,并且该元素已标记为“插入分析器”,并且创建脚本元素的HTML解析器或XML解析器的文档具有阻止脚本
样式表,则 该元素为创建元素的解析器文档的待处理的解析阻止脚本。(每个文档一次只能有一个这样的脚本。)

设置元素的“准备解析器执行”标志。解析器将处理执行脚本。

如果该元素具有src属性,没有async属性,并且没有设置“ force-async”标志,则
该元素必须添加到将尽快执行的脚本列表的末尾。在准备脚本算法开始时使用脚本元素的文档。

提取算法完成后,网络任务源将其放置在任务队列上的任务必须运行以下步骤:

如果该元素现在不是将尽快按顺序添加到上面的脚本列表中的第一个元素, 则将该元素标记为就绪,但在不执行脚本的情况下放弃这些步骤。

执行:执行与该脚本列表中的第一个脚本元素相对应的脚本块,这些脚本块将尽快执行。

从将尽快执行的脚本列表中删除第一个元素。

如果此将尽快执行的脚本列表仍然不为空,并且第一项已被标记为就绪,则跳回到标记为执行的步骤。

如果元素具有src属性 ,则必须将元素添加到将在准备脚本算法开始时尽快执行脚本元素文档的脚本集中。

一旦获取算法完成,网络任务源将放置在任务队列上的任务必须执行脚本块,然后从将尽快执行的脚本集中删除该元素。

否则 ,即使其他脚本已在执行,用户代理也必须立即执行脚本块。

那么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相对于其他脚本以任何特定顺序运行脚本。



 类似资料:
  • 使用统一的控制脚本来初始化其他脚本 我们先设置一个 Game.js 脚本作为总的控制脚本,还有另外的 Player.js、Enemy.js、Menu.js 三个脚本,那么它们的初始化过程如下: // Game.js const Player = require('Player'); const Enemy = require('Enemy'); const Menu = require('Men

  • 问题内容: 我正在尝试使用jQuery动态加载一些脚本: 但是有时加载脚本的顺序会发生变化。前一个脚本成功加载后,如何加载每个脚本? 问题答案: 您可以通过使用回调函数作为递归函数调用在前一个完成加载后加载每个。 在您的代码中发生的是,脚本是同时被请求的,并且由于它们是异步加载的,因此它们以随机顺序返回并执行。 我尚未对此进行测试,但是如果脚本是在本地托管的,则可以尝试以纯文本格式检索它们,然后将

  • 本文向大家介绍Unity3D中脚本的执行顺序和编译顺序,包括了Unity3D中脚本的执行顺序和编译顺序的使用技巧和注意事项,需要的朋友参考一下 事件函数的执行顺序 先说一下执行顺序吧。 官方给出的脚本中事件函数的执行顺序如下图: 我们可以做一个小实验来测试一下: 在Hierarchy视图中创建三个游戏对象,在Project视图中创建三条脚本,如下图所示,然后按照顺序将脚本绑定到对应的游戏对象上:

  • 问题内容: 好的,我发现必须发布一个新问题才能找到答案,这真是太荒谬了,可惜我在这里。让下一个任性的灵魂尽可能解决这个问题,让它尽可能简单。 要使ajax表单正常工作,我需要什么最新的脚本?到目前为止,我有; 我看过的页面指出我也需要jquery.unobtrusive-ajax.js,但这只是给我一个错误。是否加载了一些不兼容的版本? 过去,我已经为MVC3等进行过多次处理,但是很愚蠢的是,我似

  • 问题内容: 我正在使用jquery地址插件来加载页面,但是没有hash(#)。 index.html: page.html: 在#content div中将从page.html中加载#content html(也许我应该使用其他函数,而不是.html(),请纠正我),因为div是script标签,但是加载该页面时我没有收到警告从ajax开始,无需加载ajax就可以运行。有人能帮我吗 ? 编辑:当我

  • 我有自己的网站,当我按下一个按钮,我想加载一个不属于我的网站(即Google.com)。当这个页面加载时,我想要执行一个脚本。 例如,单击my site上的按钮,加载Google.com并用从我的网站传递的脚本文件中的值预加载搜索栏。 如果我访问Google.com时打开developer console并输入命令,我就可以做到这一点,但是,我想自动化这一点,所以我的脚本将操作这个新页面的DOM元