Laucher
2023年 11月 12日
减少 JavaScript 以提升网页性能
在现代网站开发中,减少 JavaScript 的使用是至关重要的,也是整体页面效率的关键因素。随着软件工程的发展,对于更快速、更高效的网站以及整体 JavaScript 负载更小的需求一直存在。未使用的 JavaScript 会为你的 Web 应用程序增加不必要的负担,降低整体性能。
本文将介绍一系列模式和技巧,帮助你通过去除未使用的 JavaScript 来减少这种负担,从而节省时间、优化性能并提高效率。
什么是未使用的 JavaScript?
简而言之,未使用的 JavaScript,通常称为死代码,是指你的 Web 应用程序不使用或不需要的任何代码,但存在于你发送到浏览器的最终 JavaScript 捆绑包中。这些死代码处于休眠状态,增加了你的 JavaScript 捆绑包的整体大小,可能影响性能。
为什么会有未使用的代码?
最明显的原因是你可能添加了不再需要的代码,但在最终捆绑包中忘记了删除。这些可能是在应用程序中不再执行、调用或在任何地方不再使用的函数、类或变量。
另一个原因可能是未使用的依赖关系。换句话说,你可能在代码中使用了第三方 JavaScript 依赖关系,但实际上并没有使用。更糟糕的是,这些依赖关系可能有它们自己的未使用 JavaScript,进一步增加了项目中不必要的负担。
移除未使用的 JavaScript
有几种方法可以从 Web 应用程序中删除未使用的 JavaScript。以下是一些建议和模式,将帮助你将更强大、更高效的 JavaScript 捆绑包发送到 Web,无论你是使用纯 JavaScript 还是任何专用库或框架,如 React、SolidJS 或 Vue.js。
代码拆分
代码拆分是一种将 JavaScript 代码拆分为更小、更易管理的块的技术。然后,你可以按需或并行网络请求加载这些块,这意味着你不必每次都加载整个 JavaScript 捆绑包,只需加载必要的部分。
想象一下,如果你有一个像下面这样的单一 JavaScript 捆绑包:
<script src="mainbundle.js"></script> <!-- 60kb 文件 -->
你可以将其拆分为较小的块,只有在需要时才能下载:
<script async defer src="chunk1.js"></script> <!-- 30 kb 文件 -->
<script async defer src="chunk2.js"></script> <!-- 30 kb 文件 -->
<script async defer src="chunk3.js"></script> <!-- 30 kb 文件 -->
这种策略减少了初始化和下载 JavaScript 脚本的主线程上的整体网络负载:
如果你使用 Next.js 或 Vue 等 JavaScript 库或框架,你无需手动执行此操作 — 大多数现代 JavaScript 框架默认支持代码拆分。
将一些组件委托为仅在服务器端使用
这有助于框架“智能”地将 JavaScript 进一步拆分成不应与客户端 JavaScript 捆绑在一起的更小块。
许多组织在生产中使用这种策略,这证明了其效率。以下是 Loom 网站中代码拆分的示例:
树摇(Tree Shaking)
树摇是指消除死代码,即应用程序未使用的 JavaScript。许多流行的捆绑工具,如 webpack、Rollup 或 Vite,在构建发送到浏览器的 JavaScript 块时使用了树摇的方法。
为了确保捆绑包中进行树摇,请始终在你的 JavaScript 组件中使用现代 ES6 语法 — 即 import 和 export 语法:
// 默认导入
import Navbar from 'Components'
// 命名导入
import { Navbar } from 'Components'
// 默认导出
export default Navbar
// 命名导出
export { Navbar }
现代 ES6 语法有助于你的捆绑工具识别死代码,类似于 ESLint 指出是否导入了组件,但在任何地方都没有使用。
JavaScript 缩小
捆绑包中的 JavaScript 越少,浏览器下载捆绑包所需的时间就越少。为确保 JavaScript 尽可能轻量,请在发送之前进行缩小。
JavaScript 缩小将修剪代码中不需要的部分,如空格、语法高亮、注释等。这些不必要的片段会以死代码的形式占据捆绑包中的空间。
即使是看起来简单的 JavaScript 代码也可以被压缩和修改。以下是缩小之前的简单 JavaScript 代码示例:
// add 函数
const add = (a, b) => {
return a + b
}
// 调用 add 函数
add(3, 4)
这是缩小后的代码示例:
const add=(d,a)=>d+a;add(3,4);
想象一下,在大规模捆绑包上进行 JavaScript 缩小会有什么效果!
JavaScript 缩小比你想象的要简单。你可以从许多在线提供的 JavaScript 缩小工具中进行选择,如 Terser、Uglify、babel-minify 等。
异步加载 JavaScript
一个小提示可以显著节省网络带宽的时间是始终异步加载 JavaScript。
你可以通过向你的 JavaScript 脚本添加 async
和 defer
属性来实现这一点。这将自动处理 JavaScript 下载,并且在加载 JavaScript 时不会延迟或阻止 HTML 的解析或渲染。
async
和 defer
属性以稍微不同的顺序处理 JavaScript 脚本的下载和执行。你可以根据你的项目选择最适合的。
一个async JavaScript脚本的工作方式如下图所示:
同时,一个defer JavaScript脚本是这样工作的:
在许多情况下,同时添加dec和defer可以正确地完成工作。这里有一个例子:
<script async defer src="bundle.js"></script>
动态导入
由于 ES6 模块,纯 JavaScript 中现在可以实现动态导入。当你想有条件地加载 JavaScript 模块或脚本时,这将特别有用。以下是如何编写动态导入的示例:
import('./utility.js')
.then((module) => {
// 在这里使用实用程序代码
})
.catch((error) => {
// 捕获错误
});
这种策略使我们能够在满足特定条件之后请求 JavaScript 捆绑包,而不是在文件顶部导入每个 JavaScript 组件。考虑以下代码片段,其中模块仅在附加事件侦听器后加载:
document.getElementById('dashboard').addEventListener('click', () => {
import('./utility.js')
.then((module) => {
// 使用实用模块 API
module.callSomeFunction()
})
// 在这里捕获意外错误
.catch((error) => {
console.error("Oops! An error has occurred");
});
});
惰性加载
JavaScript 中的惰性加载是一种简单但非常有用的模式。当正确使用时,惰性加载可以帮助你节省网络带宽。基本规则是仅加载当前时间所需的 JavaScript 模块。
你可以遵循的一个模式是始终在视口高度上加载 JavaScript。假设你有一个非常庞大的用户列表。你可能不想加载,比如第 300 个用户的信息,因为这些信息在当前视口中既不需要也不可见。
对于这种特定用例,有一些非常出色的库,它们将 JavaScript 模块委托给仅在达到当前视口的特定用户(例如第 300 个用户)时才加载。
惰性加载不仅限于列表。例如,图像、视频、大量节点等资源也可以进行惰性加载。例如,在浏览器下载实际图像及其相关 JavaScript 之前,你可以放置一个占位符。
这些模式不仅帮助你减少 JavaScript 代码的发送,还极大地改善了用户体验。
检查库是否已弃用
随着 JavaScript 生态系统的不断改进,你的代码和所使用的库应该跟上任何变化。这将有助于使你的代码更加健壮,为将来的发布提供更高的安全性。
如果在代码中使用任何第三方库,请确保始终使用最新版本,并检查它们是否已弃用。许多库,尤其是那些由志愿者维护的小型开源库,可能会过时或意外地被弃用。
在基于 npm 或 Node.js 的开发环境中,你可以运行以下代码来检查库是否已弃用:
npx depcheck
选择轻量级库
你选择的外部依赖项或第三方库可能会影响你发送的 JavaScript 量。始终确保你为项目选择的任何库都在积极维护,使用现代 ECMAScript 版本,最重要的是,它是轻量级的。
你可以使用类似 Bundlephobia 的工具来检查 JavaScript 大小、整体版本和特定库在慢速连接上下载所需时间。你可能会发现,与你目前使用的相比,有一个执行得更好且更轻量的库。
例如,如果使用 Bundlephobia 检查 React,你会发现它非常快速 — 在 4G 连接上仅需 3 毫秒,在慢 3g 连接上为 50 毫秒:
对于每周有数百万次下载的 JavaScript 库来说,这是相当令人印象深刻的。此外,它仅有一个依赖关系,在被缩小后仅有 6kB 多一点。
这使 React 成为在速度、JavaScript 捆绑包大小和可伸缩性方面作为项目外部依赖项的不错选择。
结论
在本文中,我们讨论了八种方法,可帮助你减少 JavaScript 的使用并提高项目的性能。
每个项目都是不同的,具有不同的架构和使用的模式。这里提到的许多技巧对你可能有用,但有些可能不适用。
请根据你和你的项目的实际情况来判断最适合你的是什么。这将使你能够自信地使你的网站和应用程序更加健壮。