我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JS 加载性能Tree Shaking优化详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JS 加载性能Tree Shaking优化详解

正文

随着 web 应用复杂性增加,JS 代码文件的大小也在不断的攀升,截住 2021年9月,在 httparchive 上有统计显示——在移动设备上 JS 传输大小大约为 447 KB,桌面端 JS 传输大小大约为 495 KB,注意这仅仅是在网络中传输的 JS 文件大小,JS 的实际大小要比传输大小大很多。

上图是下载和运行JavaScript的过程。

即使 JS 的传输大小被压缩为 300 KB,但仍然有 900 KB 的 JS 代码需要被浏览器解析、编译和执行。图像一旦被下载,浏览器只需要花费相对琐碎的解码时间,与图像不同的是,JS 必须被解析、编译,最终执行,这使得处理 JS 比处理其他类型的资源更耗时。

上图是浏览器解析/编译 170 KB的 JS 的处理成本与同等大小的 JPEG 的解码时间。JS 引擎的性能在不断被改进,改进网站 JS 性能也是开发者要做的事情。Code Splitting 是优化 JS 性能的技术之一,但是它不能减少应用程序的 JS 代码的总大小,在这里我们使用 Tree Shaking 来减小 js 代码的大小。

什么是 Tree Shaking

您可以将应用程序想象成一棵树。您实际使用的源代码和库表示树中绿色的活叶子,死代码表示秋天时树上棕色的枯叶,为了除掉枯叶,你必须摇动树,让它们掉下。Tree Shaking 是指消除死代码,下面通过一个应用程序演示了这个概念。使用 ES6 静态模块语法导入依赖项:

// 在这里导入了所有的数组处理方法
import arrayUtils from "array-utils";

在应用最初的时候,依赖项可能很少,随着功能逐渐增加,依赖项也会增加,更糟糕的是,旧的依赖项不再使用,但可能不会从代码库中删除,最终的结果是,应用程序带有大量未使用的 JS 代码,Tree Shaking 解决了这个问题,它通过分析我们在文件中使用的 ES6 静态模块语句来分析哪些模块被导入了:

// 只导入部分方法
import { unique, implode, explode } from "array-utils";

这个导入示例与前一个示例的区别在于,本示例只导入模块的特定部分,而不是从“array-utils”模块导入所有内容。

寻找 Tree Shaking 的机会

为了便于说明,这里有一个使用 webpack 的单页应用程序示例来演示 Tree Shaking 是如何工作的。界面如下:

这个程序打包之后的代码被分为两文件,如下:

在任何应用程序中,你需要从静态导入语句寻找 Tree Shaking 的机会,在示例程序中(FilterablePedalList.js)你将看到这样一行导入语句:

import * as utils from "../../utils/utils";

在文件中这样的导入语句应该引起你的注意,它的意思是:从 utils 模块导入所有内容。问题是:你真的用到所有的内容了吗?现在我们来检查 FilterablePedalList.js 中究竟使用了 utils 模块中的那些方法,通过检索发现只使用了 utils.simpleSort:

if (this.state.sortBy === "model") {
  // Simple sort gets used here...
  json = utils.simpleSort(json, "model", this.state.sortOrder);
} else if (this.state.sortBy === "type") {
  // ..and here...
  json = utils.simpleSort(json, "type", this.state.sortOrder);
} else {
  // ..and here.
  json = utils.simpleSort(json, "manufacturer", this.state.sortOrder);
}

我们现在开始做 Tree Shaking 优化

防止 Babel 将 ES6 模块转换为 CommonJS 模块

在大型应用中 Babel 是不可或缺的工具,但是它会让 Tree Shaking 变得困难。如果你正在使用 babel-preset-env,它会自动为你将 ES6 模块转换为更广泛兼容的 CommonJS 模块,即:用 require 代替 import。对于 CommonJS 模块而言做 Tree Shaking 优化非常困难,这是因为 CommonJS 模块是动态的,在构建阶段 bundlers 不容易分析出 CommonJS 模块导出了什么和导入了什么。为了避免 babel-preset-env 将 ES6 模块转换成 CommonJS 模块,我们可以这么做:

{
  "presets": [
    ["env", {
      "modules": false
    }]
  ]
}

在你的 Babel -preset-env 配置中简单指定"modules": false 就可以让 Babel 按照我们想要的方式运行,这允许 webpack 分析你的依赖树并摆脱那些未使用的依赖。

留意 side effects

当函数修改了它作用域之外的内容,我们就认为这个函数有 side effects。side effects 也适用于ES6模块,在你做 Tree Shaking 的时候你需要留意你的模块是否有 side effects(副作用),如果模块接受可预测的输入,并输出同样可预测的输出,而不修改其自身范围之外的任何内容,我们就认为这个模块没有 side effects,对于没有 side effects 的模块你可以放心的做 Tree Shaking。在这里我举两个 side effects 例子:

import './index.module.scss';
import './assets/shoot.svg';

如果在某个模块中出现了上面这样的 import 语句,则认为这个模块有 side effects,这时在做 Tree Shaking 的时候你需要小心一些。默认情况下,webpack 在做 Tree Shaking 的时候,会认为 index.module.scss 与 assets/shoot.svg 没有被用到,所以它们会被移除,如果不想被移除,可以告诉 webpack 它们是 side effects:

{
  "name": "webpack-tree-shaking-example",
  "version": "1.0.0",
  "sideEffects": [
    "./index.module.scss",
    "./assets/shoot.svg"
  ]
}

在项目的 package.json 中配置 sideEffects 字段。sideEffects 字段也能为 false,这表示项目中不存在有 side effects 的模块。

只导入你需要的

现在我们已经告诉 babel 不要将 ES6 模块转成 CommonJS 模块,现在我们需要对导入语法做一点微调,只从 utils 模块中引入我们需要的函数吗,在本指南的例子中,我们只需要 simpleSort:

import { simpleSort } from "../../utils/utils";
if (this.state.sortBy === "model") {
  json = simpleSort(json, "model", this.state.sortOrder);
} else if (this.state.sortBy === "type") {
  json = simpleSort(json, "type", this.state.sortOrder);
} else {
  json = simpleSort(json, "manufacturer", this.state.sortOrder);
}

现在我们已经完成了 Tree Shaking 的工作,下面是 Tree Shaking 之前 webpack 打包生成的 js 包大小:

                 Asset      Size  Chunks             Chunk Names
js/vendors.16262743.js  37.1 KiB       0  [emitted]  vendors
   js/main.797ebb8b.js  20.8 KiB       1  [emitted]  main

下面是 Tree Shaking 之后 webpack 打包生成的 js 包大小:

                 Asset      Size  Chunks             Chunk Names
js/vendors.45ce9b64.js  36.9 KiB       0  [emitted]  vendors
   js/main.559652be.js  8.46 KiB       1  [emitted]  main

main 的文件大小下降比较明显,这是因为 webpack 移除了不需要的 utils 方法。

更复杂的情况

在有些情况你按照上面的步骤进行 Tree Shaking,但是 webpack 还是将模块的所有内容都打包到最终的 Chunk 中了,例如:lodash。

// 仍然会导入所有的内容
import { sortBy } from "lodash";
// 这只会导入 sortBy
import sortBy from "lodash/sortBy";

如果你想要使用第一种写法,那么你还需要安装 babel-plugin-lodash。如果你使用了第三方库,你可以看一下这个库的导出是否使用了 ES6 语法,如果它的导出用的是 CommonJS 语法,例如:module.exports,那么 webpack 不能对它进行 Tree Shaking 优化。有些插件,例如:webpack-common-shake,提供了对 CommonJS 模块进行 Tree Shaking 的能力,但是它有一些限制。

总结

为了确保构建工具可以成功地优化你的应用程序,应该避免依赖 CommonJS 模块,并在整个应用程序中使用 ES6 模块语法。

以上就是JS 加载性能Tree Shaking优化详解的详细内容,更多关于JS 加载Tree Shaking的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JS 加载性能Tree Shaking优化详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

JS 加载性能Tree Shaking优化详解

这篇文章主要为大家介绍了JS 加载性能Tree Shaking优化详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-16

JS加载性能Tree Shaking优化的方法是什么

这篇文章主要介绍了JS加载性能Tree Shaking优化的方法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JS加载性能Tree Shaking优化的方法是什么文章都会有所收获,下面我们一起来看看吧。什
2023-07-04

iOS性能优化教程之页面加载速率详解

前言我认为在编码过程中时刻注意性能影响是有必要的,但凡事都有个度,不能为了性能耽误了开发进度。在时间紧急的情况下我们往往采用“quick and dirty”的方案来快速出成果,后面再迭代优化,即所谓的敏捷开发。与之相对应的是传统软件开发中
2022-05-22

Elasticsearch 性能优化详解

ES 一旦创建好索引后,就无法调整分片的设置,而在 ES 中,一个分片实际上对应一个 lucene 索引,而 lucene 索引的读写会占用很多的系统资源,因此,分片数不能设置过大;

Vue路由的懒加载与性能优化

Vue路由懒加载按需加载组件,提高初始加载速度和内存使用率。懒加载可通过组件内或路由配置中实现。此外,可通过异步组件、代码分割、预加载、服务端渲染、虚拟滚动和CDN使用优化Vue路由性能。通过结合这些技术,应用程序性能可得到显著提升。
Vue路由的懒加载与性能优化
2024-04-02

懒加载与延迟加载在PHP接口性能优化中的实践(PHP接口性能优化中懒加载与延迟加载的运用)

懒加载和延迟加载是PHP接口性能优化的有效技术。懒加载在需要时才加载资源,而延迟加载在页面加载后延迟加载非关键功能。在PHP中,可以使用lazy_load扩展实现图像懒加载。对于非关键脚本和样式表,可以使用JavaScript的defer和media="print"属性实现延迟加载。这些技术可以减少初始页面加载时间、提升响应速度和降低内存消耗,但可能会增加延迟加载后的延迟时间,并且不适用于所有资源。最佳实践包括仅对非关键资源使用懒加载和延迟加载、避免对关键内容使用延迟加载、使用适当的加载策略,并监控影响并
懒加载与延迟加载在PHP接口性能优化中的实践(PHP接口性能优化中懒加载与延迟加载的运用)
2024-04-02

Android性能优化之弱网优化详解

这篇文章主要为大家介绍了Android性能优化之弱网优化示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

Android布局性能优化之按需加载View

有时应用程序中会有一些很少用到的复杂布局。在需要它们的时候再加载可以降低内存的消耗,同时也可以加快界面的渲染速度。 定义ViewStub ViewStub是一个轻量级的View,它没有高宽,也不会绘制任何东西。所以它的加载与卸载的成本很低。
2022-06-06

JS技巧Canvas性能优化脏矩形渲染实例详解

这篇文章主要为大家介绍了JS技巧Canvas性能优化脏矩形渲染实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-16

详解GaussDB for MySQL性能优化

目录背景灵感来源于生活快递的优化原理GaussDB(for MySQL)的优化实际测试背景 我们先来看看MySQL 8.0的事务提交的大致流程以上流程,是MySQL8.0对WAL原则的一种实现,这个流程意味着,任何一个事务的提交,一定要完成
2022-05-18

Android性能优化之Bitmap图片优化详解

前言 在Android开发过程中,Bitmap往往会给开发者带来一些困扰,因为对Bitmap操作不慎,就容易造成OOM(Java.lang.OutofMemoryError - 内存溢出),本篇博客,我们将一起探讨Bitmap的性能优化。
2022-06-06

详解Android_性能优化之ViewPager加载成百上千高清大图oom解决方案

一、背景最近做项目需要用到选择图片上传,类似于微信、微博那样的图片选择器,ContentResolver读取本地图片资源并用RecyclerView+Glide加载图片显示就搞定列表的显示,这个没什么大问题,重点是,点击图片进入大图浏览,比
2022-06-06

编程热搜

目录