Answers:
不仅可以,但是你必须做出特别的努力,不,如果你不想。:-)
当浏览器script在解析HTML时遇到经典标记时,它将停止解析并移交给运行脚本的JavaScript解释器。在脚本执行完成之前,解析器不会继续(因为脚本可能会执行document.write调用解析器应处理的输出标记)。
这是默认行为,但是您可以使用一些选项来延迟脚本执行:
使用JavaScript模块。将type="module"脚本推迟到完全解析HTML并创建初始DOM之前。这不是使用模块的主要原因,而是原因之一:
<script type="module" src="./my-code.js"></script>
<!-- Or -->
<script type="module">
// Your code here
</script>
该代码将被提取(如果是单独的)并与HTML解析并行地解析,但不会运行直到HTML解析完成后。(如果您的模块代码是内联而不是在其自己的文件中,则也将其推迟到HTML解析完成之前。)
当我在2010年首次写此答案时,此功能不可用,但在2020年,所有主要的现代浏览器都将原生支持模块,如果您需要支持较旧的浏览器,则可以使用Webpack和Rollup.js等捆绑程序。
defer在经典脚本标签上使用属性:
<script defer src="./my-code.js"></script>
与该模块一样,my-code.js将与HTML解析并行地获取并解析其中的代码,但直到HTML解析完成后,该代码才会运行。但是,defer不适用于嵌入式脚本内容,仅适用于通过引用的外部文件src。
我认为这不是您想要的,但是您可以使用async属性告诉浏览器在HTML解析的同时获取JavaScript代码,但是即使HTML解析未完成,也应尽快运行它。您可以将其放在type="module"标签上,也可以代替defer经典script标签使用。
将script标签放在文档的末尾,紧接在结束</body>标签之前:
<!doctype html>
<html>
<!-- ... -->
<body>
<!-- The document's HTML goes here -->
<script type="module" src="./my-code.js"></script><!-- Or inline script -->
</body>
</html>
这样,即使代码一遇到就会立即运行,它上面的HTML定义的所有元素都存在并且可以使用。
过去,这在某些浏览器上造成了额外的延迟,因为它们script在遇到标签之前不会开始获取代码,但是现代的浏览器会向前扫描并开始预取。到目前为止,这仍然是第三选择,这两个模块defer都是更好的选择。
该规范具有有用图表示原始script标签,defer,async,type="module",和type="module" async而当JavaScript代码被取和运行的时序:
这是默认行为的示例,即原始script标签:
.found {
color: green;
}
<p>Paragraph 1</p>
<script>
if (typeof NodeList !== "undefined" && !NodeList.prototype.forEach) {
NodeList.prototype.forEach = Array.prototype.forEach;
}
document.querySelectorAll("p").forEach(p => {
p.classList.add("found");
});
</script>
<p>Paragraph 2</p>
(有关此问题的详细信息,请参见我的回答NodeList代码的。)
运行该脚本时,您会看到“段落1”为绿色,而“段落2”为黑色,因为脚本与HTML解析同步运行,因此它只能找到第一段,而不是第二段。
相比之下,这是一个type="module"脚本:
.found {
color: green;
}
<p>Paragraph 1</p>
<script type="module">
document.querySelectorAll("p").forEach(p => {
p.classList.add("found");
});
</script>
<p>Paragraph 2</p>
注意它们现在都变成绿色了。在HTML解析完成之前,代码没有运行。对于一个defer script具有外部内容(但不是内联内容)的,。
(这里不需要进行NodeList检查,因为任何现代浏览器支持模块都已forEach启用NodeList。)
在当今这个现代世界中,DOMContentLoadedPrototypeJS,jQuery,ExtJS,Dojo和大多数其他早在今天提供的“就绪”功能并没有真正的价值。只需使用模块或defer。甚至在今天,也没有太多的理由使用它们(它们经常被错误地使用,因为整个jQuery库都在文档中而不是在文档之后,所以它们script在加载整个jQuery库时阻止了页面演示head),有些开发人员Google早些时候就举报了。这也是YUI建议将脚本放到末尾的原因之一body,也是在今天。
<body onload="doIt()>"。
load事件发生非常晚在页面加载的过程,这是几乎从来没有最好的做法,以等待运行你的JavaScript在那之前。但是是的,这是一个选择。顺便说一句,我已经彻底审查了2020年的答案。
document.addEventListener('DOMContentLoaded', function(){ //doyour stuff })
您可以随时运行javascript代码。AFAIK在浏览器到达其所在的<script>标记时立即执行。但是您无法访问尚未加载的元素。
因此,如果您需要访问元素,则应等待DOM加载完毕(这并不意味着整个页面都已加载,包括图像和其他内容。这只是文档的结构,它的加载时间要早得多,因此通常您会赢(没有注意到延迟),请使用jQuery中的DOMContentLoaded事件或函数$.ready。