加载并执行脚本的顺序

时间:2012-01-25 01:33:10

标签: javascript load-order

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

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

不计算来自硬盘,javascript:URI和onEvent - 属性[3]的浏览器脚本,已经有16个替代方法可以执行JS,我确定我忘记了什么。

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

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

4 个答案:

答案 0 :(得分:11)

浏览器将按照找到的顺序执行脚本。如果您调用外部脚本,它将阻止页面,直到脚本加载并执行。

测试这个事实:

// file: test.php
sleep(10);
die("alert('Done!');");

// HTML file:
<script type="text/javascript" src="test.php"></script>

动态添加的脚本会在附加到文档后立即执行。

测试这个事实:

<!DOCTYPE HTML>
<html>
<head>
    <title>Test</title>
</head>
<body>
    <script type="text/javascript">
        var s = document.createElement('script');
        s.type = "text/javascript";
        s.src = "link.js"; // file contains alert("hello!");
        document.body.appendChild(s);
        alert("appended");
    </script>
    <script type="text/javascript">
        alert("final");
    </script>
</body>
</html>

警报顺序是“附加” - &gt; “你好!” - &GT; “最终”

如果您在脚本中尝试访问尚未到达的元素(例如:<script>do something with #blah</script><div id="blah"></div>),那么您将收到错误。

总的来说,是的,您可以包含外部脚本,然后访问其功能和变量,但前提是您退出当前的<script>标记并开始新标记。

答案 1 :(得分:2)

答案 2 :(得分:1)

在测试了许多选项之后,我发现以下简单的解决方案是按照在所有现代浏览器中添加动态加载脚本的顺序来加载动态加载脚本

loadScripts(sources) {
    sources.forEach(src => {
        var script = document.createElement('script');
        script.src = src;
        script.async = false; //<-- the important part
        document.body.appendChild( script ); //<-- make sure to append to body instead of head 
    });
}

loadScripts(['/scr/script1.js','src/script2.js'])

答案 3 :(得分:0)

我无法理解如何在 onload 事件发生之前执行嵌入式模块脚本。上面的答案有很大帮助,但让我添加部分答案,说明是什么解决了我对“加载和执行脚本的顺序”的误解的特定问题。

我第一次使用 ... 这导致了一个奇怪的问题,它在正常加载页面时可以正常工作,但在 FireFox 上的调试器中运行时却无法正常工作。这让调试变得非常困难。

注意:类型为“module”的脚本总是有一个隐含的“deferred”属性,这意味着它们不会停止解析 html,这意味着 onload-event 可以在脚本执行之前发生。我不想那样。但我确实想使用 type="module" 使我未导出的 JavaScript 函数和变量对同一页面上的其他脚本不可见。

我尝试了不同的选项,但由于上述答案,我了解到如果将 async 属性添加到类型为 module 的脚本中,则意味着该脚本会异步加载,但一旦加载它就会立即执行。

但就我而言,这是嵌入在 HTML 页面中的脚本。因此,它意味着不需要“异步”加载。它已经与页面一起加载,因为它已嵌入其中。因此,带有此更改的它确实会立即执行——这正是我想要的。

所以我认为有必要指出这个特定情况,因为它有点违反直觉:要立即执行嵌入的脚本,您必须将 ASYNC 属性添加到其标记中。

通常人们可能认为“异步”意味着某些事情以不确定的顺序异步发生,而不是立即发生。但要意识到的是,“async”导致异步加载,但加载完成后立即执行。嵌入脚本后,无需加载,因此您可以立即执行。

总结:使用

     <script type="module" async> ... </script>

获取嵌入到 HTML 页面的模块脚本以立即执行。