logo
Laucher

Laucher

Laucher

2023年 11月 12日

0

减少 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 网站中代码拆分的示例:

JavaScript脚本的主线程上的总体网络负载
JavaScript脚本的主线程上的总体网络负载

树摇(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 脚本添加 asyncdefer 属性来实现这一点。这将自动处理 JavaScript 下载,并且在加载 JavaScript 时不会延迟或阻止 HTML 的解析或渲染。

asyncdefer 属性以稍微不同的顺序处理 JavaScript 脚本的下载和执行。你可以根据你的项目选择最适合的。

一个async JavaScript脚本的工作方式如下图所示:

async JavaScript脚本
async JavaScript脚本

同时,一个defer JavaScript脚本是这样工作的:

defer 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 毫秒:

LogRocket
LogRocket

对于每周有数百万次下载的 JavaScript 库来说,这是相当令人印象深刻的。此外,它仅有一个依赖关系,在被缩小后仅有 6kB 多一点。

这使 React 成为在速度、JavaScript 捆绑包大小和可伸缩性方面作为项目外部依赖项的不错选择。

结论

在本文中,我们讨论了八种方法,可帮助你减少 JavaScript 的使用并提高项目的性能。

每个项目都是不同的,具有不同的架构和使用的模式。这里提到的许多技巧对你可能有用,但有些可能不适用。

请根据你和你的项目的实际情况来判断最适合你的是什么。这将使你能够自信地使你的网站和应用程序更加健壮。

评论