JavaScript 加载技术和性能
将外部脚本文件添加到您的 HTML 文档非常简单,您可以在睡梦中完成。
但这并不像你想象的那么简单。在哪里以及如何添加脚本文件,会严重影响网站的性能。
这篇博文是关于什么的?
在这篇文章中,我们将介绍将外部脚本文件包含到 HTML 中的技术,并研究这如何影响性能。
我们将比较在不同情况下哪种技术更可取、更有效。
先决条件
这篇博文假设您熟悉基本的 HTML、CSS 和 JavaScript 语法。
我们还将学习以下属性:async
和defer
。
介绍
-
您可能已经知道,外部 JavaScript 文件可以包含在:
- 头
- 身体
-
在我们继续深入讨论这些技术之前,让我们先了解一下浏览器加载网页时会发生什么。
- 浏览器获取请求的 HTML 文件,并对其进行解析。
- 解析后的 HTML 包含对外部脚本和样式表的引用。
- 这些外部引用被获取、解析/加载。
- 一旦加载,表单中的样式就会应用到 DOM 元素上,并且
- 然后执行加载的脚本并应用到页面,用户查看完成的视觉结构。
- 本质上,这应该是获取、解析、加载和执行发生的顺序。
- JavaScript 文件应该在 DOM 完成后最终应用。但这可能会根据您添加脚本文件的位置而有所不同。
好了,说得够多了!我们开始正文吧!
在正文中包含脚本
- 这是最受欢迎的技术,因为该策略可确保 HTML 在脚本文件之前进行解析。
- 当您的脚本操作 DOM 元素时,此顺序是必要的。
<!DOCTYPE html>
<html>
<head>
<title>JavaScript reference inside body</title>
</head>
<body>
<!-- DOCUMENT CONTENT -->
<script src="./src/main.js"></script>
</body>
</html>
<script>
自从我开始学习 JavaScript 以来,我一直在 HTML 主体中添加。- 但直到最近我才知道,这是一种老式的方法,而且令人惊讶的是,它不再是推荐的方法。
- 在主体中添加脚本引用可能会给 DOM 内容加载时间,但一个主要问题是 JavaScript 加载被阻止。
- 当您的网站中有多个(并且庞大!)脚本时,它可能会变成一场噩梦,因为用户必须等待脚本加载然后执行。
- 这不仅会降低网站的性能,还会让用户感到沮丧。
- 因为用户讨厌等待网站加载!
我们如何设法加载 JavaScript 文件,同时保留用户体验并优化网站性能?
对此的简单回答是:在头部添加脚本引用
在头部包含脚本
- 是的,你没看错。在 中添加脚本引用
<head>
。
<!DOCTYPE html>
<html>
<head>
<title>JavaScript reference inside body</title>
<!-- Add script file source here -->
<script src="./src/main.js"></script>
</head>
<body>
<!-- DOCUMENT CONTENT -->
</body>
</html>
- 但事情并没有那么简单。还有一个问题是,当你将脚本文件添加到 时
<head>
,脚本文件会在HTML DOM 完全解析和加载之前被获取。 <p>
下面显示的图像描述了一个示例网页,当用户单击按钮时会显示一条消息。-
出现错误“无法读取 null 的 addEventListener 属性”。这是因为 DOM 是在 JavaScript 获取之后加载的,因此没有对按钮的引用。
- 但这也是可以避免的。怎么做呢?这样做:
document.addEventListener('DOMContentLoaded', function() {
btn.addEventListener('click', () => {
p.textContent = "You clicked me!";
});
});
- 上述代码向主体添加了一个事件监听器,用于监听 DOM 内容的加载。
- 一旦内容加载完毕,处理程序函数内的所有代码都会被执行,从而确保只有在 DOM 完全加载后才会执行 JavaScript。
-
HTML5 提供了两个新的现代功能,可防止阻塞 HTML 解析和 JavaScript 加载。
-
当脚本标签包含在.js文件中时,会添加两个属性:
async
and(或)。defer
<head>
-
这两个属性都要求浏览器在单独的线程中加载脚本文件,而不会阻止 HTML 文件的解析。
1. 异步
<!DOCTYPE html>
<html>
<head>
<title>JavaScript reference inside body</title>
<!-- Add script file source here -->
<script src="./src/main.js" async></script>
</head>
<body>
<!-- DOCUMENT CONTENT -->
</body>
</html>
- 此属性确保脚本文件的加载不会影响 HTML 的解析。
- 也就是说,浏览器在解析 HTML 的同时加载/获取脚本文件。
- HTML 解析没有暂停,因此脚本文件的加载不会阻止 DOM 加载。
- 但是一旦脚本文件完全加载,HTML 解析就会暂停,脚本会立即执行,从而阻止 DOM 加载。
- 当您的网页有多个脚本时,无法保证脚本的获取、加载和执行的顺序与脚本在 HTML 文件中出现的顺序相同。
- 因此在以下情况下使用此属性:
- 脚本的获取、加载和执行彼此独立。也就是说,一个脚本中的代码不会影响另一个脚本中的代码。
- 当您需要脚本执行实际执行开始之前所需的初始化任务时。
- 当您拥有不操作 DOM 的脚本时。
<head>
<!-- Add script file source here -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous" async></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous" async></script>
<script src="./src/init.js" async></script>
</head>
- 例如:在上面的代码中,无法保证首先获取并执行 jQuery,然后是 Bootstrap,然后是 init 脚本。
- 顺序可以说是:首先执行 Bootstrap,然后执行 init,最后执行 jQuery 脚本。
2. 推迟
<!DOCTYPE html>
<html>
<head>
<title>JavaScript reference inside body</title>
<!-- Add script file source here -->
<script src="./src/main.js" defer></script>
</head>
<body>
<!-- DOCUMENT CONTENT -->
</body>
</html>
- defer,顾名思义,就是在单独的线程中加载脚本文件,但是推迟脚本文件的执行。
- 与 不同
async
,文件加载后不会立即执行脚本,并且不会阻止 DOM 加载。 - 此属性确保仅当 DOM 完全加载时才执行脚本。
- 获取、加载和执行脚本的顺序与它们在中出现的顺序相同
<head>
。
- 因此在以下情况下使用此属性:
- 您的网页中的脚本文件相互依赖,一个脚本的执行会影响另一个脚本。
- 当你的脚本操作 DOM 内容时。
<head>
<!-- Add script file source here -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous" defer></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous" defer></script>
<script src="./src/main.js" defer></script>
</head>
- 上述代码中脚本的执行顺序为:jQuery脚本、Bootstrap、最后是主脚本文件。
结论
<body>
根据经验法则,我建议仅当您的网站使用的脚本很少时才添加脚本源。-
如果您有多个繁重的脚本,请在块内引用它
<head>
作为源,<body>
以阻止 JavaScript 加载,从而影响您网站的性能。 -
如果您的网站中的脚本彼此独立,并且您想在主 JavaScript 加载之前执行代码,请使用异步。
-
当您的脚本依赖于 HTML 解析和 DOM 元素操作时,请使用 defer。
- 这是来自MDN 文档的 HTML 解析以及 JavaScript 加载和执行的直观表示。
非常感谢你的支持和阅读这篇博文。
请分享给你的朋友,并在评论区写下你对这篇文章的感受。
如果您喜欢这篇文章并从中学到了东西,请做心、保存、独角兽或全部做!
鏂囩珷鏉ユ簮锛�https://dev.to/bharati21/javascript-loading-techniques-performance-56lp