社区精选 | 前端性能优化(图文并茂,通俗易懂)

业界 作者:SegmentFault 2022-10-06 12:58:00

今天小编为大家带来的是社区作者 寒水寺一禅 的文章。看看他如何讲解前端性能优化。


一、静态和动态导入



默认情况下,我们静态导入的所有模块都会添加到初始捆绑包中。使用默认 ES2015 导入语法 导入的模块将静态导入。

import module from 'module'


实际上,我们可以而把那些在需要时展示的组件,通过动态导入来实现

import("b.vue").then()  //动态导入,在打包时会自动chunk


如上图,在点击时 emoji 时,才去加载 emoji-picker 组件。

动态路由和动态组件会自动拆分bundle。


二、可见性导入



除了用户交互之外,我们通常还有在初始页面上不可见的组件。一个很好的例子是延迟加载图像,这些图像在视口中不直接可见,但只有在用户向下滚动后才会加载。


三、交互时导入(懒惰式加载)



当用户与需要它的 UI 交互时,延迟加载非关键资源

您的页面可能包含不是立即必需的组件或资源的代码或数据。例如,用户看不到用户界面的一部分,除非他们单击或滚动页面的某些部分。例如模态框、列表的详情页、视频播放器或聊天小部件、第三方资源等等

与其立即加载这些资源,不如在更合适的时刻加载它们,例如:

  • 当用户首次单击以与该组件进行交互时
  • 将组件滚动到视图中
  • 或延迟该组件的加载,直到浏览器空闲(通过 requestIdleCallback API)。

加载资源的不同方法概括如下:

  • 立即加载资源(加载脚本的正常方式)
  • Lazy (路由)- 当用户导航到路由或组件时加载
  • Lazy (交互时) - 当用户单击 UI 时加载(例如显示聊天)
  • Lazy (在视口中)- 当用户滚动到组件时加载
  • Prefetch - 预拉取
  • Preload - 预加载

如: 第三方 UI


如: 视频播放器嵌入


如: 认证


如:聊天小部件


如: 帮助页



四、基于路由的拆分



根据当前路由动态加载组件

{
    path: "/home",
    component: () => import(/* webpackChunkName: "home"*/  "@/components/layout/Index.vue"),
    children: [
      //todo     
    ],
},


五、捆绑拆分



将代码拆分为可重用的小块

构建现代 Web 应用程序时,打包器例如,Webpack或rollup获取应用程序的源代码,并将其打包到一个或多个bundle中,
当用户访问网站时, bundle请求并加载,以便将数据显示到用户的屏幕。

bundle越大,则浏览器引擎到达进行第一次呈现调用的行所需的时间越长。在那之前,用户必须盯着空白屏幕相当长一段时间,这可能是.非常令人沮丧!

我们希望尽快向用户显示数据。更大的bundle导致加载时间、处理时间和执行时间增加.如果我们能减小这个捆绑包的大小,以便加快速度,那就太好了。


六、断续器模式



通过预缓存、延迟加载和最小化往返来优化初始负载

当我们想要访问一个网站时,我们首先必须向服务器发出请求才能获得这些资源。入口点指向的文件从服务器返回,这通常是我们应用程序的初始HTML文件!浏览器的 HTML 解析器在开始从服务器接收此数据后立即开始解析此数据。如果解析器发现需要更多资源(如样式表或脚本),则会向服务器发送另一个 HTTP 请求以获取这些资源!


断续器模式侧重于四个主要的性能注意事项:

  • 有效地推送关键资源,从而最大限度地减少到服务器的往返量并减少加载时间。
  • 尽快渲染初始路由,提升用户体验
  • 在后台为经常访问的路由预缓存资源,以最大限度地减少对服务器的请求量并实现更好的脱机体验
  • 懒惰地加载不经常请求的路线或资源


七、Tree Shaking



通过消除死代码来减小捆绑包大小

我们可能会将代码添加到我们的捆绑包中,而这些代码在应用程序中的任何地方都没有使用。这段死代码可以消除,以减小捆包的尺寸,并防止不必要地加载更多数据!消除死代码的过程在将其添加到我们的捆绑包之前,称为tree-shaking


八、Preload



在发现关键资源之前通知浏览器(指关键资源加载完后,会接着加载preload的资源。)

<link rel="preload"> 方式



webpackPreload: true 方式(Webpack 4.6.0+)
const EmojiPicker = import(/* webpackPreload: true */ "./EmojiPicker");


九、Prefetch
取和缓存可能很快请求的资源(指关键资源加载完后,不一定会加载prefetch的资源,可能等到具体需要时才加载)
<link rel="prefetch">方式

webpackPrefetch: true方式
const EmojiPicker = import(/* webpackPrefetch: true */ "./EmojiPicker");


十、虚拟列表



这是在动态列表中仅呈现可见内容行而不是整个列表的想法。呈现的行只是完整列表的一小部分,当用户滚动时,可见的内容(窗口)会移动。这可以提高渲染性能。


十一、压缩脚本



减少通过网络传输脚本所需的时间

  • Gzip 和 Brotli 是两种最常用的被现在浏览器所支持的 压缩js 方式(需要和nginx配置使用)
  • Brotli 在相似的压缩级别下提供了更好的压缩比(但是需要https,而gzip在http下也可以)
  • 如果你使用 webpack来打包你得代码,你可以使用 CompressionPlugin 压缩为gzip 或者 使用 BrotliWebpackPlugin 压缩为brotli,如果使用rollup,则使用rollup-plugin-gzip插件
  • Gzip压缩切换到Brotli压缩,文件体积大小会降低15%-25%左右。
  • compress(a + b) <= compress(a) + compress(b) - 单个大捆绑包将比多个较小的捆绑包提供更好的压缩

HTTP 数据压缩可以以不同的方式进行分类。其中之一是有损与无损。
有损压缩意味着压缩-解压缩循环会导致文档略有更改,同时保持其可用性。最终用户大多无法察觉到这种变化。有损压缩最常见的示例是图像的 JPEG 压缩。
使用无损压缩,压缩和后续解压缩后恢复的数据将与原始数据精确匹配。PNG 图像是无损压缩的一个示例。无损压缩与文本传输相关,应应用于基于文本的格式,如 HTML、CSS 和 JavaScript。

有多个工具可用于缩小 HTML、CSS 和 JS 资源。Terser 是 ES6+ 中流行的 JavaScript 压缩工具,默认情况下,Webpack 包含一个用于此库的插件,用于创建缩小的构建文件。

也可以使用esbuild压缩,它是一种比terser速度还快的压缩方式。能快10-100倍。

静态与动态压缩


缩小有助于显著减小文件大小,但压缩 JS 可以提供更显著的增益。可以通过两种方式实现服务器端压缩。

静态压缩:可以使用静态压缩来预压缩资源,并在生成过程中提前保存它们。常用于打包时压缩。比如webpack或者rollup在打包时,就提前压缩为gzip,然后放到 nginx上,配置 gzip_static:on;这样在http请求时,会获取 gzip的文件,然后浏览器解压缩,显示页面。

动态压缩:通过此过程,当浏览器请求资源时,压缩会动态进行。常用于接口中的数据压缩,在请求接口时,服务器动态压缩数据,然后返回到浏览器。

Gzip 和Brotli算法


Gzip压缩格式已经存在了近30年,是一种基于Deflate算法的无损算法。Deflate算法本身使用LZ77算法和霍夫曼编码的组合。

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


所有主流浏览器都支持 Gzip。

Brotli

2015年,谷歌推出了Brotli算法和Brotli压缩数据格式。与GZip一样,Brotli也是一种基于LZ77算法和霍夫曼编码的无损算法。此外,它还使用二阶上下文建模以类似的速度产生更密集的压缩。上下文建模是一项功能,它允许在同一块中对同一字母表使用多个霍夫曼树。Brotli 还支持更大的窗口大小用于反向引用,并具有静态字典。这些功能有助于提高其作为压缩算法的效率。

Brotli目前受到所有主要服务器和浏览器的支持,并且越来越受欢迎。

比较gzip和brotli


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


启用压缩


webpack配置

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

Nginx 这样的 HTTP 代理上启用它

server {
        listen 8080;
        server_name localhost;

        # 需要http_gzip_static_module 模块
        gzip_static on;  
        
        location / {
            alias html
            index index.html index.htm;
            try_files $uri $uri/ /html/index.html;
        }
}

浏览器通过请求中的 Accept-Encoding HTTP 标头传达它支持的压缩算法,这表明浏览器支持 Gzip 和brotli
Accept-Encoding: gzip, br

服务器将返回 Content-Encoding HTTP 响应标头,以指示响应中使用的压缩算法。例如,
Content-Encoding: br

关注公众号:拾黑(shiheibook)了解更多

赞助链接:

关注数据与安全,洞悉企业级服务市场:https://www.ijiandao.com/
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接