本文详细介绍了提升JavaScript加载速度的10种关键技术,包括懒加载、最小化、打包、代码拆分、Tree Shaking、ES模块、CDN、缓存、压缩以及使用Lighthouse进行性能审计。通过合理应用这些技术,可以显著减少加载时间,提升用户体验和网站转化率。
1. 懒加载
并非所有JavaScript代码都需在用户首次访问网站时加载。例如,若页面底部设有邮箱注册功能,除非用户滚动至该区域,否则无需提前加载。因此,许多Web开发者采用懒加载技术,即按需加载当前所需的JavaScript部分,而非一次性加载全部脚本。
懒加载的实现方式多样。若某些元素无需立即交互,但需尽快可用,可在页面加载完成后使用 requestIdleCallback()。或者,如前所述,若页面底部存在无需立即交互的元素,可使用 intersectionObserver 监听该元素,当用户滚动至该区域时再加载相关脚本。
实现代码懒加载的最佳方式是动态 import,它是ESM(ECMAScript Modules)的一部分。使用 import() 允许在任何时刻加载JavaScript。例如,以下代码将在浏览器空闲时加载一个JavaScript文件:
requestIdleCallback(() => {
import("/script.mjs");
});另一种懒加载实现方式是利用 script 标签的 async 和 defer 属性。该技术虽缺乏扩展性,但能简单实现DOM加载完成后加载JavaScript的需求。
2. 最小化
最小化是提升性能的直接方法,通常通过Terser或ESBuild等自动化工具完成。这些工具通过移除空格、长变量名以及开发中有用但会增加生产环境脚本大小的内容来缩小代码体积。例如,假设使用Terser对以下代码进行缩减:
window.addEventListener("DOMContentLoaded", (event) => {
const images = document.getElementsByTagName("img");
for (const image of images) {
image.width = 50;
image.height = 50;
}
});最终结果为:
window.addEventListener("DOMContentLoaded", (e) => {
const t = document.getElementsByTagName("img");
for (const e of t) (e.width = 50), (e.height = 50);
});代码体积减少了67个字节,从203个字节缩减至136字节!虽然这一差异看似微小,但对于大型脚本,最小化可产生显著影响。
3. Bundling
脚本大小并非唯一关键因素,请求数量同样重要,因为每个请求都会增加开销。理想情况下,应将脚本数量保持在最低限度。然而,代码拆分通常是保持代码整洁的最佳实践。幸运的是,类似于最小化工具,存在自动化工具来解决此问题,即捆绑器(Bundlers)。捆绑器分析代码,查看脚本间的导入关系,并确定如何组合它们。最知名的捆绑器包括Webpack、Rollup和Vite。
使用捆绑器的另一大优势是,大多数捆绑器也可作为构建工具,简化最小化和TypeScript编译等任务。有关捆绑器的更多信息,请参阅笔者关于捆绑器的文章。
4. 代码拆分
这可能在打包之后进行。"我打包代码只是为了将其拆分?"并非如此。事实上,这也是打包工具的功能之一。虽然减少请求数量是好事,但不希望用户一次性加载网站的所有代码。虽然可以为每个页面创建独立的完整打包程序,但这会削弱缓存的一些优势(后文将讨论)。为解决此问题,我们采用代码拆分。代码拆分结合了打包和懒加载的优点,同时确保不加载页面无关的代码。打包工具通过分析导入映射来执行代码分割,确定哪些脚本需放入独立的捆绑包中。大多数打包工具可自动完成此过程,尽管编写易于分析的代码(例如尽可能使用静态导入)会有所帮助。
5. Tree Shaking
捆绑器的另一常见功能是Tree Shaking(树摇)。你可能仅导入库的一部分,但不需要其他部分。若未启用Tree Shaking,最终用户将加载整个库,这可能导致JavaScript体积大幅增加。Tree Shaking解决了这一问题;支持Tree Shaking的捆绑器会自动删除库中未使用的部分,从而大幅减少导入的代码量。例如,查看Lodash(具体为lodash-es),一个大型JavaScript工具库。整个模块近100千字节,但若仅使用intersect()函数,仅导入2.7千字节的代码。虽然Lodash提供了一些仅包含单个函数的包,但若使用大量函数,这些包的使用会较为繁琐,且许多库并未提供此类单函数包。
6. ES 模块
为使前述许多功能发挥作用,ECMAScript Modules(ESM)至关重要。ESM是一种模块规范,旨在规范不同文件间的代码共享方式。在ESM出现之前,存在相互冲突的标准,如CommonJS和UMD,且它们并未被浏览器原生支持。ESM统一了这些标准,并提供了有助于实现Tree Shaking等功能的语法(注意前文提到使用lodash-es而非标准lodash)。此外,由于ESM在浏览器中获原生支持,无需依赖沉重的polyfill即可使用ESM。
// ESM
import { something } from "test";
export const something = "test";
// CJS
const something = require("test").something;
module.exports.something = "test";7. CDN
在自有服务器上托管静态文件并无必要。使用完整的服务器进行实际的服务器端计算会增加成本、开发复杂性和网站加载时间。相反,CDN(内容分发网络)是更优解决方案。CDN是一个服务器网络,旨在快速且廉价地提供静态文件。你可以从数十或数百个服务器(取决于CDN提供商)提供文件,而非仅从一个服务器提供服务,从而降低延迟,因为服务器离用户更近。此外,CDN通常为你配置缓存和压缩等功能,节省时间。一些流行的CDN示例包括Cloudflare CDN和亚马逊的CloudFront。
8. 缓存
虽然首次加载体验至关重要,但你也需考虑重复访问者的性能。使重复访问显著加速的一种方法是通过缓存。浏览器缓存的作用是保存网站资源的副本,并使用该副本而非再次下载。这意味着重复访问几乎即时完成。要设置缓存,需在响应中为要缓存的资源设置Cache-Control头。若使用CDN,这很可能已自动配置。若未使用,设置过程也很简单。
9. 压缩
你可能已遇到过.zip或.tar.gz文件。你可能也知道,在将目录转化为文件的同时,它们也减少了文件大小。大小的减少是通过压缩完成的。压缩的工作原理是运行一种算法,通过缩小重复语句并执行其他操作来使文件变小,具体取决于使用的算法。有许多流行的压缩算法,如deflate、lz4、Brotli和Zstandard。zip和gzipped文件使用的压缩算法是deflate。
实现压缩可能有些复杂,但也有简单方法。最简单的方法是使用能自动压缩文件的CDN,如前文第7点所述。另一种实现压缩的简单方法是运行支持压缩的文件服务器。然而,若无法实现以上两点,还有其他解决方案。许多构建工具/捆绑器都有自动生成压缩形式文件的插件,你可将其提供给浏览器以自动解压。浏览器通过Accept-Encoding头告知其支持的压缩算法,而服务器通过Content-Encoding头告知浏览器在响应中使用何种压缩算法。欲了解更多信息,请参阅MDN关于HTTP压缩的文章。
10. Lighthouse
Lighthouse是一个帮助你自动审核网站性能的工具,同时还包括其他一些类别,如搜索引擎优化和可访问性。它对于发现性能问题并提供解决这些问题的便捷途径非常有帮助。如果你有Chrome或其他基于Chromium的浏览器,Lighthouse应该是默认可用的。如果你使用其他浏览器,你可以下载扩展程序或使用PageSpeed Insights。PageSpeed Insights还提供了来自真实用户的数据,如果你想了解用户的实际体验,这将会很有帮助。
总结
有了这些提示,你应该在你的网站上取得较大的性能收益,转化为更多的保留和转换。
以上就是提升JavaScript加载速度的10种方式的详细内容,更多关于提升JavaScript加载速度的资料请关注本站其它相关文章!