大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。
JavaScript 对于创建交互式 Web 体验至关重要,其发展大大增强了 Web 的动态性。JavaScript 从下载、解析到执行的每个阶段都需要大量的浏览器资源。太少的 JavaScript 可能会损害用户体验和业务目标,而过度使用则会导致加载时间缓慢、页面响应迟钝和用户参与度低。
本文将重估 JavaScript 在 Web 上的作用,并为设计流畅、高效的用户体验提供建议。但是,因为篇幅有限,关于动态导入、Web workers、代码或图片压缩技术、Source Maps、Interaction to Next Paint (INP)、Total Blocking Time (TBT)、Long Tasks 、Scheduler API、Synchronous XHR等主题可以参考文末资料。
1. 页面应该加载多少 JavaScript
JavaScript 的体积大小一直在持续增加,2024 年 JavaScript 的负载中位数增长了 14%,在移动设备上达到 558kb,在桌面上达到 613kb。
这种持续增长的体积趋势确实令人担忧。虽然设备功能正在不断改进,但并非每个用户都能使用最新技术。同时,更大的 JavaScript 包体积会给设备资源带来额外的压力,从而影响性能,尤其是对于使用较旧或功能较弱的硬件用户而言。
2. 每个页面应该有多少个 JavaScript 请求
网页上的每个资源都会触发至少一个请求,同时如果该资源请求其他资源,请求量就会迅速增加。
对于脚本请求,风险更高。发送的请求越多,加载的 JavaScript 就越多,同时触发瓶颈的可能性就越大,因为脚本会在主线程上争夺资源。这种资源争夺可能会影响性能,例如:延迟启动等。
<script type="module" src="main.js"></script>
<script nomodule src="fallback.js"></script>
// 加载js文件
import { name as squareName, draw } from "./shapes/square.js";
import { name as circleName } from "https://example.com/shapes/circle.js";
// 引入ESM 方式
2024 年,移动页面中位数发出 22 个 JavaScript 请求,而第 90 个百分位数的请求飙升至 68 个。与去年相比,中位数增加了 1 个请求,第 90 个百分位数增加了 4 个请求,是一个微妙但明显的增长。
桌面端情况类似,中位数跃升至 23 个 JavaScript 请求,第 90 个百分位数攀升至 70 个请求。明显看到中位数增加了 1 个请求,第 90 个百分位数增加了 5 个请求。
虽然这些增长乍一看似乎影响不大,但其标志着网络行为的持续演变。自 2019 年以来 JavaScript 请求数量稳步增长,这预示着未来 JavaScript 请求增长速度可能会大大超过性能改进速度。
随着 JavaScript 的增加,未使用的 JavaScript 字节数也在增加,大约有一半下载的字节在页面加载期间未使用。
开发者可以通过Chrome开发者工具的Coverage面板查看未使用的字节数
3.JavaScript 打包器和转译器现状
JavaScript 打包器和转译器通过优化应用程序的构建和交付方式改变了 Web 开发,例如: webpack 和 Parcel 通过将多个文件打包成一个 Bundle,从而减少了 HTTP 请求数量并缩短了加载时间。
const path = require('path');
module.exports = {
entry: './src/index.js',
// 指定入口文件
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
};
而 Babel 类似的转译器允许开发人员使用现代 JavaScript 功能,同时确保跨浏览器的兼容性。
3.1 打包器
webpack 和 Parcel 等 JavaScript 打包器将多个 JavaScript 文件打包成一个 Bundle 以简化用户交付。其分析代码及其依赖项,优化最终输出以减少 HTTP 请求的数量。通过合并文件,打包器可以缩短加载时间和提高性能。
虽然 Webpack 在所有网站上的使用率仍稳定在 5%,但最近的趋势表明,在移动和桌面端排名前 1,000 的网站中,Webpack 的使用率有所下降。
Parcel 是 webpack 第二大热门替代方案,在开发者中的采用率很高。然而,最近的趋势表明其使用率有所下降,从去年移动网站的 1.3% 下降到今年的 0.3%。桌面平台也出现了类似的情况,反映出 JavaScript 打包工具格局的转变。
Parcel 使用工作线程并行构建代码,利用计算机上的所有核心
3.2 转译器
如下图所述:
排名前 10,000 的移动网站中有 12% 使用 Babel,无论排名如何,移动网站的采用率始终高于桌面网站。这些趋势凸显了 Babel 的突出地位,尤其是在顶级和移动优化网站中,表明其在现代网络开发中的重要性日益提高。
4. 网页请求 JavaScript 方式的转换
在快节奏的 Web 开发中,JavaScript 的加载方式可以决定网站的性能。
4.1 async、defer、module 和 nomodule
Script Attributes Example
<script async src="async-script.js"></script>
<script defer src="defer-script.js"></script>
<script type="module" src="module-script.js"></script>
<script nomodule src="nomodule-script.js"></script>
Script Attributes Example
在优化 JavaScript 加载时,开发人员可以使用几个强大的属性,例如:
- async 属性允许脚本在 HTML 解析继续时异步加载,并在脚本可用时立即执行。
- defer 属性将脚本执行推迟到 HTML 解析完成之后,且保持延迟脚本的顺序。
对于现代 Web 应用程序,module 属性表示脚本是 JavaScript 模块,默认情况下启用 ES6 导入 / 导出语法和严格模式。同时,nomodule 属性还为不支持 ES6 模块的浏览器指定了回退脚本,确保了更广泛的兼容性。
如上图所述,2024 年 async 使用率显著增加,桌面和移动设备上的页面使用率从 76% 增加到 87%。 defer 使用率从 42% 略微增加到 47%, async 和 defer 属性的组合从 28-29% 略微下降到 22%。
module 使用率仍然很低,为 4%,而 nomodule 显示采用率极低甚至为零,这表明现代 JavaScript 模块系统仍未在网络上广泛流行。
4.2 preload, prefetch 和 modulepreload
资源提示在优化浏览器性能方面发挥着至关重要的作用,其指示哪些资源应该尽早获取。Preload 用于获取当前导航所需的资源,确保关键资产在需要时立即可用。
Resource Preloading Example
Resource Preloading Example
<script src="critical.js"></script>
Modulepreload 具有类似的用途,其用于预加载 JavaScript 模块,帮助高效加载模块化脚本。另一方面,Prefetch 是为下一次导航所需的资源而设计的,其允许浏览器预测并为未来的页面转换做好准备。
preload 的使用率从 2022 年桌面版的 16.4% 大幅下降到 2024 年 7.5%。prefetch 的采用率从 2022 年的约 1.0% 大幅增加到 2024 年的整体 4.8%。模块预加载的使用率在这两年都保持在非常低的水平,2022 年徘徊在 0.1% 左右,2024 年也显示出类似的低百分比 0.7%。
4.3 注入脚本
脚本注入使用 document.createElement 创建 HTMLScriptElement 并通过 DOM 插入方法将其添加到 DOM,或使用 innerHTML 将 <script> 标记作为字符串注入。虽然在许多用例中很常见,但这种做法会绕过浏览器的预加载扫描器,使脚本在初始 HTML 解析期间无法检测到,从而对性能指标 LCP 产生负面影响,尤其是当注入的脚本触发长任务或动态解析大量标记时。
// 创建一个新的 script 元素
var script = document.createElement('script');
// 设置脚本的来源(src)
script.src = 'https://example.com/your-script.js';
// 可选:设置脚本的类型(type),通常为 'text/javascript'
script.type = 'text/javascript';
// 可选:设置脚本在加载完成后执行的回调函数
script.onload = function() {
console.log('脚本加载完成并执行');
};
// 可选:设置脚本加载失败时的回调函数
script.onerror = function() {
console.error('脚本加载失败');
};
// 将脚本元素插入到文档的 head 或 body 中
document.head.appendChild(script);
// 或者 document.body.appendChild(script);
2024 年的图表显示,第 50 个百分位数的注入脚本百分比显着下降,从 2022 年的 25% 上升到 2024 年的 21%。在更高的百分位数,两年之间的趋势保持一致,2022 年和 2024 年的第 90 个百分位数都有 70% 的脚本被注入。早期百分位数的注入略有上升,但总体而言,脚本注入的模式在较高的资源水平上保持稳定。
5. JavaScript 框架使用占比
如上图所述,jQuery 仍然是网络上使用最广泛的库,出现在 74% 的页面上。这很大程度上要归功于 WordPress,但即使在 WordPress 之外,jQuery 仍然是许多网站的主导选择。
core-js (41%) 的广泛采用也是意料之中的,因为许多 Web 应用程序都依赖于 Babel,而 Babel 经常使用 core-js 为缺失的 JavaScript 功能提供 polyfill。随着浏览器不断发展并原生支持更多现代功能,这个数字应该会下降,从而减少 Web 应用程序中不必要的字节。
jQuery Migrate 出现在 33% 的页面上,这表明大量网站仍然依赖较旧的 jQuery 版本。同样,jQuery UI 仍在 22% 的页面上使用,尽管大部分已被弃用。
React 的使用率较去年的 8% 略有增长,达到 10%,但由于 JavaScript 生态系统竞争加剧,其增长已趋于平稳。与此同时,GSAP(9%)、OWL Carousel(8%)、Slick(8%)、LazySizes(8%)和 FancyBox(7%)等库继续得到广泛使用,尤其是在性能和动画密集型应用程序中。
随着 Web 生态系统不断现代化,我们预计其中一些遗留库(尤其是基于 jQuery 的库)将随着时间的推移而逐渐减少,转而采用更原生的解决方案和现代框架。
参考资料
本篇文章大部分内容来自Abdul Haddi Amjad和 Nishu Goel发布的文章《A Report on How the Web is Really Using JavaScript》,但是对部分内容进行了修改。
https://almanac.httparchive.org/en/2024/javascript
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
https://webpack.js.org/
https://parceljs.org/