在html页面中包含JavaScript有很多不同的方法。我知道以下几种选择:
内联代码或从外部URI加载
包含在<head>或<body>标签中[1,2]
没有,延迟或异步属性(仅外部脚本)
包含在静态源代码中或由其他脚本动态添加(在不同的解析状态下,使用不同的方法)
不包括来自硬盘的浏览器脚本,javascript: uri和onEvent-attributes[3],已经有16个选项来执行JS,我确定我忘记了一些东西。
我不太关心快速(并行)加载,我更好奇的是执行顺序(这可能取决于加载顺序和文档顺序)。是否有一个好的(跨浏览器的)参考可以涵盖所有的情况?例如,http://www.websiteoptimization.com/speed/tweak/defer/只处理其中的6种浏览器,并且测试的大多是旧浏览器。
因为我担心没有,这是我的具体问题:我有一些初始化和脚本加载的(外部)头部脚本。然后在正文的末尾有两个静态的内联脚本。第一个允许脚本加载器动态地将另一个脚本元素(引用外部js)追加到主体。第二个静态内联脚本希望使用来自添加的外部脚本的js。它可以依赖于另一个已经被执行(为什么:-)?
浏览器将按照找到脚本的顺序执行脚本。如果调用外部脚本,它将阻塞页面,直到脚本被加载和执行。
为了验证这一事实:
// 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>
警报的顺序是“追加”->“你好!”- - - - - - >“最终”
如果在一个脚本中,你试图访问一个还没有到达的元素(例如:<script>do something with #blah</script><div id="blah"></div>),那么你会得到一个错误。
总的来说,您可以包含外部脚本,然后访问它们的函数和变量,但前提是退出当前的<script>标记并开始一个新的标记。
我在理解如何在onload事件发生之前执行嵌入式模块脚本时遇到了麻烦。上面的回答很有帮助,但让我补充一个部分的答案,关于什么解决了我误解“脚本的加载和执行顺序”的特定问题。
我第一次使用……这导致了一个奇怪的问题,它在正常加载页面时工作,但在FireFox的调试器中运行时不工作。这使得调试变得非常困难。
注意:类型为“module”的脚本总是有一个隐式的“deferred”属性,这意味着它们不会停止html的解析,这意味着onload-event可以在脚本执行之前发生。我不想那样。但我确实想使用type="module"使我未导出的JavaScript函数和变量对同一页面上的其他脚本不可见。
我尝试了不同的选项,但多亏了上面的答案,我得到了一个见解,如果你添加async -属性到一个模块类型的脚本,这意味着脚本异步加载,但一旦加载它立即执行。
但在我的例子中,这是一个嵌入在HTML页面中的脚本。因此,这意味着不需要“异步”加载。它已经与页面一起加载,因为它是嵌入在页面中的。因此,它与这个更改立即执行—这是我想要的。
因此,我认为有必要指出这个特定的情况,因为它有点违反直觉:要立即执行一个嵌入式脚本,必须将ASYNC属性添加到它的标记中。
通常,人们可能认为“异步”意味着某些事情以异步方式发生,不确定顺序,而不是立即发生。但要意识到的是,“async”导致异步加载,但加载完成后立即执行。当脚本被嵌入时,不需要加载,因此可以立即执行。
摘要:使用
<script type="module" async> ... </script>
让嵌入到html页面的模块脚本立即执行。
浏览器将按照找到脚本的顺序执行脚本。如果调用外部脚本,它将阻塞页面,直到脚本被加载和执行。
为了验证这一事实:
// 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>
警报的顺序是“追加”->“你好!”- - - - - - >“最终”
如果在一个脚本中,你试图访问一个还没有到达的元素(例如:<script>do something with #blah</script><div id="blah"></div>),那么你会得到一个错误。
总的来说,您可以包含外部脚本,然后访问它们的函数和变量,但前提是退出当前的<script>标记并开始一个新的标记。
完美匹配您的查询!
如果没有一个解决方案为您工作,那么请参考下面的解决方案,我已经从我的方面。
我也在寻找解决方案,但在搜索了很多之后,我总结了我的代码如下,这对我来说是完美的!
这是有用的,当你想要这样的功能,在前一个脚本完全加载后,然后只加载下一个脚本!
只需创建一个名为jsLoadScripts.js的文件,并将其插入到头部或主体的底部。
//From Shree Aum Software Solutions
//aumsoftwaresolutions@gmail.com
//script incrementor for array
scriptIncrementor = 0;
//define your script urls here
let scripts = [
"https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js",
"jsGlobalFunctions.js",
"jsDateParser.js",
"jsErrorLogger.js",
"jsGlobalVariables.js",
"jsAjaxCalls.js",
"jsFieldsValidator.js",
"jsTableClickEvent.js",
"index.js",
"jsOnDocumentReady.js",
];
//it starts with the first script and then adds event listener to it. which will load another script on load of it. then this chain goes on and on by adding dynamic event listeners to the next scripts!
function initializeScripts() {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = scripts[scriptIncrementor];
document.head.appendChild(script);
script.addEventListener("load", function () {
loadNextScript();
scriptIncrementor++;
});
}
// this function adds event listener to the scripts passed to it and does not allow next script load until previous one has been loaded!
function loadNextScript() {
if (scriptIncrementor != scripts.length - 1) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = scripts[scriptIncrementor + 1];
document.head.appendChild(script);
script.addEventListener("load", function () {
loadNextScript();
scriptIncrementor++;
});
}
}
// start fetching your scripts
window.onload = function () {
initializeScripts();
};
这可能会导致一些与速度相关的问题,因此,您可以根据自定义需求调用函数initializeScripts() !