我可以在加载整个页面之前运行 javascript 吗?

IT技术 javascript html
2021-01-24 09:03:10

我想在整个页面加载之前运行一些 javascript。这可能吗?还是代码开始执行</html>

2个回答

不仅可以,但是你必须做出特别的努力,,如果你不想。:-)

当浏览器script在解析 HTML 时遇到经典标签时,它会停止解析并移交给运行脚本的 JavaScript 解释器。解析器在脚本执行完成之前不会继续(因为脚本可能会document.write调用解析器应该处理的输出标记)。

这是默认行为,但您有一些延迟脚本执行的选项:

  1. 使用 JavaScript module。一个type="module"脚本被推迟,直到HTML已经完全解析和初始DOM创建。这不是使用module的主要原因,但这是原因之一:

    <script type="module" src="./my-code.js"></script>
    <!-- Or -->
    <script type="module">
    // Your code here
    </script>
    

    代码将被提取(如果它是单独的)并与 HTML 解析并行解析,但在 HTML 解析完成之前不会运行(如果你的module代码是内联的,而不是在它自己的文件中,它也会被推迟到 HTML 解析完成。)

    当我在 2010 年第一次写这个答案时,这不可用,但在 2020 年,所有主要的现代浏览器都原生支持module,如果你需要支持旧浏览器,你可以使用 Webpack 和 Rollup.js 之类的捆绑器。

  2. defer在经典脚本标签上使用该属性:

    <script defer src="./my-code.js"></script>
    

    与module一样,代码my-code.js将与 HTML 解析并行获取和解析,但在 HTML 解析完成之前不会运行但是defer不适用于内联脚本内容,仅适用于通过src.

  3. 我认为这不是想要的,但是您可以使用该async属性告诉浏览器在解析 HTML 的同时获取 JavaScript 代码,然后尽快运行它,即使 HTML 解析未完成. 你可以把它放在一个type="module"标签上,或者用它来代替defer经典script标签。

  4. 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在遇到标记之前不会开始获取代码,但现代浏览器会提前扫描并开始预取。尽管如此,这在这一点上仍然是第三种选择,这两个moduledefer都是更好的选择。

该规范具有有用图表示原始script标签,deferasynctype="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那里进行检查,因为任何现代浏览器支持module已经在forEachNodeList。)

在这个现代世界中,DOMContentLoadedPrototypeJS、jQuery、ExtJS、Dojo 和大多数其他人在当天提供(并且仍然提供)的“就绪”功能事件没有真正的value只需使用module或defer. 即使在过去,也没有太多理由使用它们(并且它们经常被错误地使用,在加载整个 jQuery 库时阻止页面呈现,因为它scripthead文档中而不是在文档之后),一些开发人员在谷歌很早就标记了。这也是YUI 建议将脚本放在 . 末尾的部分原因body,再次回到当天。

@JustinLiu -该load事件发生非常晚在页面加载的过程,这是几乎从来没有最好的做法,以等待运行你的JavaScript在那之前。但是,是的,这是一种选择。顺便说一句,我已经彻底修改了 2020 年的答案。
2021-03-15 09:03:10
或者你可以使用 document.addEventListener('DOMContentLoaded', function(){ //doyour stuff })
2021-03-25 09:03:10
@JustinLiu - 是的,请参阅最后一段。:-) 我从来没有看到任何需要,但你可以。
2021-03-27 09:03:10
@JustinLiu - 这开始变得太过分了。如果您想发布答案,请发布答案。
2021-04-05 09:03:10
或者把它全部放在一个函数中,然后把它放在<body onload="doIt()>".
2021-04-06 09:03:10

您可以随时运行 javascript 代码。AFAIK 它是在浏览器到达它所在的 <script> 标记的那一刻执行的。但是您无法访问尚未加载的元素。

所以如果你需要访问元素,你应该等到DOM被加载(这并不意味着整个页面都被加载了,包括图像和东西。它只是文档的结构,它加载得更早,所以你通常会赢没有注意到延迟),使用jQuery 中DOMContentLoaded事件或函数$.ready

DOMContentLoaded 事件将在 DOM 层次结构完全构建后立即触发,当所有图像和子帧加载完成后,load 事件将执行此操作。
2021-03-23 09:03:10