压缩 JavaScript

压缩 JavaScript 并关注压缩后的块大小以实现最佳性能。过高的 JavaScript 打包粒度有助于消除重复项和缓存,但可能在 50-100 块范围内受到较差的压缩和加载影响(由于浏览器进程、缓存检查等)。最终,选择最适合您的压缩策略。

JavaScript 是导致页面大小增大的第二大因素,也是互联网上仅次于图像的请求量第二大的网络资源。我们使用一些模式来减少 JavaScript 的传输、加载和执行时间,以提高网站的性能。压缩可以帮助减少通过网络传输脚本所需的时间。

您可以将压缩与其他技术(如缩小、代码分割、打包、缓存和延迟加载)结合使用,以减少大量 JavaScript 对性能的影响。然而,这些技术的目标有时可能会发生冲突。本节将探讨JavaScript压缩技术,并讨论在决定代码分割和压缩策略时应考虑的问题。

  • Gzip 和 Brotli 是压缩 JavaScript 和 受到现代浏览器的广泛支持。
  • Brotli 在相似的压缩下提供更好的压缩比 水平。
  • Next.js默认提供 Gzip 压缩,但建议在 Nginx 等 HTTP 代理上启用它。
  • 如果您使用 Webpack 打包代码,则可以使用 CompressionPlugin 进行 Gzip 压缩,或者使用 BrotliWebpackPlugin 进行 Brotli 压缩。
  • Oyo 减少了 15-20%,Wix 在切换到 Brotli 压缩而不是 Gzip 后,文件大小减少了 21-25%。
  • compress(a + b) <= compress(a) + compress(b) - 一个大 bundle 包比多个较小的bundle 包有更好的压缩效果。这导致粒度的权衡,其中去重和缓存与浏览器性能和压缩存在矛盾。粒度分块可以帮助处理这种权衡。

HTTP 压缩

压缩减小了文档和文件的大小,因此它们占用的磁盘空间比原始文件少。较小的文档消耗的带宽较低,并且可以通过网络快速传输。HTTP 压缩使用这个简单的概念来压缩网站内容、减少页面权重、降低带宽要求并提高性能。

HTTP 数据压缩可以以不同的方式分类。其中之一是有损与无损。

有损压缩意味着压缩-解压缩循环会导致文档发生细微变化,同时保留其可用性。 对于最终用户来说,这种变化通常是察觉不到的。 最常见的有损压缩示例是用于图像的JPEG压缩。

无损压缩后,经过压缩和随后解压的数据将与原始数据完全匹配。PNG 图像就是无损压缩的一个例子。无损压缩与文本传输有关,应应用于基于文本的格式,如 HTML、CSS 和 JavaScript。

由于您希望在浏览器上使用所有有效的 JS 代码,因此您应该对 JavaScript 代码使用无损压缩算法。在压缩 JS 之前,缩小有助于消除不必要的语法,并将其简化为仅执行所需的代码。

缩小

若要减小负载大小,可以在压缩之前缩小 JavaScript。缩小通过删除空格和任何不必要的代码来创建更小但完全有效的代码文件,从而补充压缩。在编写代码时,我们使用换行符、缩进、空格、命名良好的变量和注释来提高代码的可读性和可维护性。但是,这些元素会影响整体 JavaScript 大小,并且不是在浏览器上执行所必需的。缩小将 JavaScript 代码减少到成功执行所需的最小值。

缩小是 JS 和 CSS 优化的标准做法。JavaScript 库开发人员通常会为生产部署提供其文件的缩小版本,通常用 min.js 名称扩展名表示。(例如,jquery.js 和 jquery.min.js

有多种工具可用于缩小 HTML、CSS 和 JS 资源。Terser 是 ES6+ 上流行的 JavaScript 压缩工具,Webpack v4 默认包含该库的插件,用于创建缩小的构建文件。您还可以将 TerserWebpackPlugin 与旧版本的 Webpack 一起使用,或者将 Terser 用作没有模块打包器的 CLI 工具。

静态压缩与动态压缩

最小化有助于显著减少文件大小,但压缩JS可以提供更显著的收益。你可以在服务器端以两种方式实现压缩。

静态压缩:您可以使用静态压缩来预压缩资源,并在生成过程中提前保存它们。在这种情况下,您可以使用更高的压缩级别来缩短代码的下载时间。较长的构建时间不会影响网站性能。最好对不经常更改的文件使用静态压缩。

动态压缩:通过此过程,当浏览器请求资源时,会即时进行压缩。动态压缩更易于实现,但仅限于使用较低的压缩级别。更高的压缩级别将需要更多的时间,并且您将失去从较小的内容大小中获得的优势。如果对频繁更改或应用程序生成的内容使用动态压缩,这将有所帮助。

您可以使用静态或动态压缩,具体取决于应用程序内容的类型。您可以使用常用的压缩算法启用静态和动态压缩,但每种情况下建议的压缩级别都不同。让我们看一下压缩算法来更好地理解这一点。

压缩算法

Gzip 和 Brotli 是当今用于压缩 HTTP 数据的两种最常用算法。

Gzip

Gzip 压缩格式已经存在了近 30 年,是一种基于 Deflate 算法的无损算法。deflate 算法本身结合使用 LZ77 算法和霍夫曼编码对输入数据流中的数据块进行编码。

LZ77 算法识别重复的字符串,并将它们替换为反向引用,反向引用是指向它之前出现的位置的指针,后跟字符串的长度。随后,霍夫曼编码识别常用的引用,并用具有较短位序列的引用替换它们。较长的位序列用于表示不常用的引用。

Image Courtesy: https://www.youtube.com/watch?v=whGwm0Lky2s&t=851s
图片提供:https://www.youtube.com/watch?v=whGwm0Lky2s&t=851s

所有主流浏览器都支持 Gzip。Zopfli 压缩算法是 Deflate/Gzip 的较慢但改进的版本,可生成较小的 GZip 兼容文件。它最适合静态压缩,可以提供更显着的增益。

Brotli

2015 年,Google 推出了 Brotli 算法和 Brotli 压缩数据格式。与 GZip 一样,Brotli 也是一种基于 LZ77 算法和霍夫曼编码的无损算法。此外,它还使用二阶上下文建模以相似的速度产生更密集的压缩。上下文建模是一项功能,它允许在同一块中为同一字母表使用多个霍夫曼树。Brotli 还支持更大的反向引用窗口大小,并具有静态字典。这些功能有助于提高其作为压缩算法的效率。
如今,所有主要服务器和浏览器都支持Brotli,并且越来越受欢迎。托管服务提供商和中间件(包括 Netlify、AWS 和 Vercel)也支持并轻松启用它。

拥有庞大用户群的网站,如OYO和Wix,在用Brotli取代Gzip后,其性能得到了显着提高。

下表显示了不同压缩级别下 Brotli 和 Gzip 压缩比和速度的基准比较。

此外,以下是 Chrome 研究对使用 Gzip 和 Brotli 压缩 JS 的一些见解

  • Gzip 9 具有最佳的压缩率和良好的压缩速度,您应该考虑在其他级别的 Gzip 之前使用它。
  • 对于 Brotli,请考虑 6-11 级。否则,我们可以用 Gzip 更快地实现类似的压缩率。
  • 在所有尺寸范围内,Brotli 9-11 的性能都比 Gzip 好得多,但它的速度相当慢。
  •  bundle 包越大,压缩率和速度就越好。
  • 对于所有包大小,算法之间的关系都是相似的(例如,对于每个包大小,Brotli 7 都比 Gzip 9 好,对于所有大小范围,Gzip 9 都比 Brotli 5 快)。

现在让我们看一下服务器和浏览器之间关于所选压缩格式的通信。

启用压缩

您可以在构建过程中启用静态压缩。如果您使用 Webpack 打包代码,则可以使用 CompressionPlugin 进行 Gzip 压缩,或者使用 BrotliWebpackPlugin 进行 Brotli 压缩。该插件可以包含在 Webpack 配置文件中,如下所示。

module.exports = {
  //...
  plugins: [
    //...
    new CompressionPlugin(),
  ],
};

 Next.js默认提供 Gzip 压缩,但建议在 Nginx 等 HTTP 代理上启用它。Gzip 和 Brotli 在 Vercel 平台上的代理级别都受支持。

您可以在支持不同压缩算法的服务器(包括Node.js)上启用动态无损压缩。浏览器通过请求中的 Accept-Encoding HTTP 标头传达它支持的压缩算法。例如,Accept-Encoding: gzip, br.

这表明浏览器支持 Gzip 和 Brotli。您可以按照特定服务器类型的说明在服务器上启用不同类型的压缩。例如,您可以在此处找到在 Apache 服务器上启用 Brotli 的说明。Express 是 Node 的流行 Web 框架,它提供了一个压缩中间件库。使用它来压缩请求的任何资源。

审核压缩

可以在 Chrome -> DevTools -> network -> Headers 中检查服务器是否压缩了下载的脚本或文本。DevTools 显示响应中使用的内容编码,如下所示。

lighthouse 报告包括对“启用文本压缩”的性能审计,该审计检查在未将内容编码标头设置为“br”、“gzip”或“deflate”的情况下接收的基于文本的资源类型。Lighthouse 使用 Gzip 来计算资源的潜在节省。

 图片提供:​​​​​​https://web.dev/uses-text-compression/#how-to-enable-text-compression-on-your-server

JavaScript 压缩和加载粒度

 要完全掌握 JavaScript 压缩的效果,您还必须考虑 JavaScript 优化的其他方面,例如基于路由的拆分、代码拆分和打包。

具有大量 JavaScript 代码的现代 Web 应用程序通常使用不同的代码拆分和打包技术来有效地加载代码。应用使用逻辑边界来拆分代码,例如单页应用程序的路由级别拆分,或在交互或视口可见性上增量提供 JavaScript。您可以配置打包程序以识别这些边界。

在继续讨论代码拆分和打包如何影响压缩之前,让我们介绍一些与代码拆分和打包相关的基本定义。

打包术语

模块:模块是离散的功能块,旨在提供可靠的抽象和封装。有关详细信息,请参阅模块模式。

Bundle:包含源文件的最终版本并已在捆绑程序中完成加载和编译过程的不同模块组。

Bundle splitting:  打包程序用于将应用程序拆分为多个 bundle 包的过程,以便可以独立隔离、发布、下载或缓存每个 bundle 包。

Chunk: 在Webpack术语中,chunk是打包和代码分割过程的最终输出。Webpack可以根据 entry  配置、SplitChunksPlugin或动态导入来将捆绑包分割成多个chunk。

如果模块包含在源文件中,则代码或打包拆分后构建过程的最终输出称为chunk。请注意,源文件和 chunk 可能相互依赖。

图片提供:https://www.youtube.com/watch?v=ImjzA7EMI6I&list=PLyspMSh4XhLP-mqulUMcaqTbLo-ZJxSX5&index=29

 JavaScript 的输出大小是指 JavaScript 打包器或编译器优化后的块大小或原始大小。大型 JS 应用程序可以解构为可独立加载的 JavaScript 文件块。加载粒度是指输出块的数量,块的数量越多,每个块的大小越小,粒度越高。

某些块比其他块更重要,因为它们的加载频率更高,或者是更有影响力的代码路径的一部分(例如,加载“checkout”小部件)。要知道哪些块最重要,需要应用知识,但可以肯定的是,“基本”块始终是必不可少的。

页面所需的区块的每个字节都需要由用户设备下载并解析/执行。这是直接影响应用程序性能的代码。由于块是最终将下载的代码,因此压缩块可以带来更好的下载速度。

在此背景下,让我们讨论加载粒度和压缩之间的相互作用。

粒度权衡

1、提高下载速度:如前面的部分所示,可以使用压缩来提高下载速度。但是,与使用相同代码压缩多个小块相比,压缩一个大块将产生更好的结果或更小的文件大小。

compress(a + b) <= compress(a) + compress(b)

有限的本地数据表明,较小的区块损失为 5% 到 10%。在未捆绑块的极端情况下,大小增加了 20%。额外的 IPC、I/O 和处理成本附加到每个块,如果块较大,则共享这些块。v8 引擎具有 30K 的流式处理/分析阈值。这意味着所有小于 30K 的块都将在关键加载路径上解析,即使它是非关键的。

由于上述原因,对于相同的代码,较大的块可能比较小的块更有效,以优化下载和浏览器性能。

2、提高缓存命中率和缓存效率:较小的块可提高缓存效率,尤其是对于以增量方式加载 JS 的应用。

  • 更改被隔离为具有较小块的较少块。如果发生代码更改,则只需要重新下载受影响的块,并且与这些块对应的代码大小可能很小。因此,可以在缓存中找到剩余的块,从而增加缓存命中的数量。
  • 对于较大的块,可能会影响大量代码,并且需要在代码更改后重新下载。

因此,较小的块是利用缓存机制的理想。

3、**快速执行 **- 要使代码快速执行,它应满足以下条件。

  • 所有必需的依赖项都随时可用 - 它们已一起下载或在缓存中可用。这意味着您应该将所有相关代码捆绑在一起,作为一个更大的块。
  • 只应执行页面/路由所需的代码。这要求不下载或执行额外的代码。包含常见依赖项的commons块可能具有大多数(但不是所有页面)所需的依赖项。重复数据删除代码需要更小的独立块。
  • 主线程上的长任务可能会长时间阻塞它。因此,这些需要分解成更小的块。

如上面的三角形所示,试图优化上述目标之一的加载粒度可能会使您远离其他目标。这就是粒度权衡的问题。

重复数据删除和缓存与浏览器性能和压缩不一致。

由于这种权衡,大多数生产应用程序目前使用的最大块数约为 10 个。需要增加此限制,以支持对具有大量 JavaScript 的应用进行更好的缓存和重复数据消除。

SplitChunksPlugin 和 Granular chunking

粒度权衡的潜在解决方案将满足以下要求。

1、允许使用更小的块大小来容纳更多块(40 到 100 个),以便在不影响性能的情况下更好地缓存和删除重复数据。

2、解决由于 IPC、I/O 和许多脚本标记的处理成本而导致的多个较小块的性能开销。

3、解决多个较小块情况下的压缩损失问题。

满足这些要求的潜在解决方案仍在开发中。但是,Webpack v4 的 SplitChunksPlugin 和粒度分块策略可以在一定程度上帮助增加加载粒度。

早期版本的 Webpack 使用 CommonsChunkPlugin 将公共依赖项或共享模块捆绑到单个块中。这可能会导致不使用这些通用模块的页面的下载和执行时间不必要地增加。为了更好地优化这些页面,Webpack 在 v4 中引入了 SplitChunksPlugin。根据默认值或配置创建多个拆分块,以防止跨各种路由获取重复代码。

Next.js采用了 SplitChunksPlugin 并实现了以下 Granular Chunking 策略来生成解决粒度权衡的 Webpack 块。

  • 任何足够大的第三方模块(大于 160 KB)都会被拆分为单独的块。
  • 为框架依赖项创建单独的框架块。(react、react-dom 等)
  • 根据需要创建任意数量的共享块。(最多 25 个)
  • 要生成的块的最小大小更改为 20 KB。

发出多个共享块而不是单个块可以最大程度地减少在不同页面上下载或执行的不必要(或重复)代码的数量。为大型第三方库生成独立的块可以改进缓存,因为它们不太可能经常更改。最小块大小为 20 kB,可确保压缩损耗相当低。

精细的分块策略帮助几个 Next JS 应用程序减少了网站使用的 JavaScript 总量。

在 Gatsby 中也实施了颗粒化分块策略,观察到类似的益处。

结论 

仅靠压缩并不能解决所有 JavaScript 性能问题,但了解浏览器和打包程序在幕后的工作方式有助于创建更好的打包策略,从而支持更好的压缩。加载粒度问题需要在生态系统中的不同平台上解决。颗粒分块可能是朝着这个方向迈出的一步,但我们还有很长的路要走。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/517357.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯刷题day13——玩游戏【算法赛】

一、问题描述 小 A 和小 B 两个人在海边找到了 n 个石子&#xff0c;准备开始进行一些游戏&#xff0c;具体规则如下&#xff1a;小 B 首先将 n 个石子分成若干堆&#xff0c;接下来从小 A 开始小 A 和小 B 轮流取石子&#xff0c;每次可以任选一堆石子取走任意个&#xff0c;…

(CVPR2024)DragGAN作者新作DiffMorpher:可以实现两张图像间的平滑变形

相信大家在网上看过一些图像变换的动图以及视频。比如生成两张人脸之间的渐变图。 狮子变老虎 那么这种功能是如何实现的呢&#xff1f; 计算机科学中有一种专门描述此应用的任务—图像变形(image morphing)。给定两张图像&#xff0c;图像变形算法会输出一系列合理的插值图像…

Redis数据库:概念、安装及常用操作命令

目录 前言 一、数据库概述 1、关系型数据库&#xff08;RDBMS&#xff09; 1.1 产生背景 1.2 概念 1.3 特点 1.4 优缺点 1.5 常见主流关系型数据库 2、非关系型数据库&#xff08;NoSQL&#xff09; 2.1 产生背景 2.2 概念 2.3 特点 2.4 优缺点 2.5 常见主流非关…

Mybatis--TypeHandler使用手册

TypeHandler使用手册 场景&#xff1a;想保存user时 teacher自动转String &#xff0c;不想每次保存都要手动去转String&#xff1b;从DB查询出来时&#xff0c;也要自动帮我们转换成Java对象 Teacher Data public class User {private Integer id;private String name;priva…

labview如何创建2D多曲线XY图和3D图

1如何使用labview创建2D多曲线图 使用“索引与捆绑簇数组”函数将多个一维数组捆绑成一个簇的数组&#xff0c;然后将结果赋值给XY图&#xff0c;这样一个多曲线XY图就生成了。也可以自己去手动索引&#xff0c;手动捆绑并生成数组&#xff0c;结果是一样的 2.如何创建3D图 在…

hadoop在linux上启动成功了,但是浏览器访问不了

根据网上的资料进行安装hadoop的伪集群 都安装成功&#xff0c;并且启动也成功了&#xff0c;如下图所示&#xff1a; 2、但是在浏览器上确是怎么也访问不了&#xff0c; 解决思路&#xff0c; 2.1、根据网上的一些文章处理解决是关闭防火墙&#xff0c; 2.1.1、我根据操作步骤…

【Python】RGB颜色对照表

专栏文章索引&#xff1a;Python 这里是我收集的几个RGB颜色对照网站&#xff1a; RGB颜色对照表 (oschina.net) RGB Color Codes Chart &#x1f3a8; (rapidtables.com) Colors RGB and RGBA (w3schools.com) Color Hex - ColorHexa.com Color Picker — HTML Color Cod…

CSRF介绍及Python实现

CSRF 文章目录 CSRF1. CSRF是什么&#xff1f;2. CSRF可以做什么&#xff1f;3. CSRF漏洞现状4. CSRF的原理5. 举例说明6. CSRF的防御Python示例 1. CSRF是什么&#xff1f; CSRF&#xff08;Cross-Site Request Forgery&#xff09;&#xff0c;中文名称&#xff1a;跨站请求…

按照指定的分隔符和次数从右侧开始分割字符串元素numpy.char.rsplit()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 按照指定的分隔符和次数 从右侧开始分割字符串元素 numpy.char.rsplit() [太阳]选择题 请问关于以下代码表述错误的选项是&#xff1f; import numpy as np a np.array([a b c, x,y,z, 1 2,…

江协STM32:定时器定时中断和定时器定时闹钟

定时器中断 新建文件 按这个图来编写程序 第一步&#xff1a;RCC开启时钟&#xff0c;定时器到基准时钟和整个外设到工作时钟就会同时打开 第二步&#xff1a;选择时基单元的时钟源&#xff0c;对于定时中断选择内部时钟源 第三步&#xff1a;配置时基单元&#xff0c;ARR,P…

Linux第2课Windows下的环境配置-虚拟机安装

文章目录 Linux第2课Windows下的环境配置-虚拟机安装一、VMware虚拟机的安装&#xff08;一&#xff09;安装VMware&#xff08;二&#xff09;启动电脑本地的VMware相关服务 二、VirtualBox安装 Linux第2课Windows下的环境配置-虚拟机安装 本节课程提供了两种虚拟机的安装方法…

【Django开发】0到1美多商城项目md教程第5篇:短信验证码,1. 避免频繁发送短信验证码逻辑分析【附代码文档】

美多商城完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;欢迎来到美多商城&#xff01;&#xff0c;项目准备。展示用户注册页面&#xff0c;创建用户模块子应用。用户注册业务实现&#xff0c;用户注册前端逻辑。图形验证码&#xff0c;图形验证码接口设…

Java笔试题总结

HashSet子类依靠()方法区分重复元素。 A toString(),equals() B clone(),equals() C hashCode(),equals() D getClass(),clone() 答案:C 解析: 先调用对象的hashcode方法将对象映射为数组下标,再通过equals来判断元素内容是否相同 以下程序执行的结果是&#xff1a; class X{…

NKCTF2024 re VM?VM!WP

逻辑似乎很简单&#xff08;个鬼啊&#xff09; 这个函数是把输入的字符转化为二进制并倒序存储 sub_1570太大了加载不出来&#xff0c;应该是加密的主逻辑&#xff0c;目的是需要输出1 可以通过删除栈的方法强行转化伪代码 首先删掉这部分 9A0改小点 这个也是 栈这里U一下再…

通讯录(顺序表的应用)

文章目录 顺序表思想实现通讯录头文件接口函数主函数 顺序表思想实现通讯录 实现通讯录前&#xff0c;我们考虑一下&#xff0c;通讯录需要包含什么内容&#xff1f; 联系人&#xff0c;联系人需要包含姓名年龄电话性别这3种基本信息。 我们知道顺序表实质是个数组&#xff…

【C++】C++中的list

一、介绍 官方给的 list的文档介绍 简单来说就是&#xff1a; list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中…

浅谈TCP(2):流量控制与拥塞控制

上文浅谈TCP&#xff08;1&#xff09;&#xff1a;状态机与重传机制介绍了TCP的状态机与重传机制。本文介绍流量控制&#xff08;Flow Control&#xff0c;简称流控&#xff09;与拥塞控制&#xff08;Congestion Control&#xff09;。TCP依此保障网络的QOS&#xff08;Quali…

【Leetcode每日一题】 递归 - 求根节点到叶节点数字之和(难度⭐⭐)(50)

1. 题目解析 题目链接&#xff1a;814. 二叉树剪枝 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 想象一下&#xff0c;你有一堆层层叠叠的积木&#xff0c;你想从底部开始&#xff0c;把那些标记为0的积木拿走。如…

【QT+QGIS跨平台编译】056:【PDAL+Qt跨平台编译】(pdalcpp错误处理)

点击查看专栏目录 文章目录 一、报错信息:二、原因分析三、解决思路四、原版FileUtils.cpp五、修改后的FileUtils.cpp一、报错信息: ① exists is unavaiable: introduced in macOS 10.15 ② create_directory is unavaiable: introduced in macOS 10.15 ③ create_director…

BCLinux-for-Euler配置本地yum源

稍微吐槽一句…… 在这片土地上&#xff0c;国产化软件的大潮正在滚滚而来&#xff0c;虽然都不是真正意义上的国产化&#xff0c;但是至少壳是国产的~~~ 之前使用的Centos7的系统&#xff0c;现在都要求统一换成BCLinux-for-Euler。说实话换了之后不太适应&#xff0c;好多用习…