必看!2024 年 Web 双端使用 JavaScript 的全新趋势

家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Script Attributes Example</title>
    <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>
</head>
<body>
    <h1>Script Attributes Example</h1>
</body>
</html>

在优化 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 用于获取当前导航所需的资源,确保关键资产在需要时立即可用。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Resource Preloading Example</title>
    <!-- Preload critical resources -->
    <link rel="preload" href="critical.js" as="script">
    <link rel="preload" href="important.css" as="style">
    <link rel="prefetch" href="optional.js">
    <link rel="prefetch" href="optional.css">
    <link rel="modulepreload" href="module.js">
</head>
<body>
    <h1>Resource Preloading Example</h1>
    <script src="critical.js"></script>
    <link rel="stylesheet" href="important.css">
</body>
</html>

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/