- 代码执行更快
- 文件加载更快,首屏加载优化
- webpack性能优化
代码层面:避免使用css表达式,避免使用高级选择器,通配选择器。
缓存利用:缓存Ajax,使用CDN,使用外部js和css文件以便缓存,添加Expires头,服务端配置Etag,减少DNS查找等
请求数量:合并样式和脚本,使用css图片精灵,初始首屏之外的图片资源按需加载,静态资源延迟加载。
请求带宽:压缩文件,开启GZIP,
编码优化
html 优化:
- 减少 dom 数量,避免不必要的节点或嵌套;
css 优化:
- 使用
<link>
替代原生 @import; - 特定的选择器 好过一层一层查找: .xxx-child-text{} 优于 .xxx .child .text{}
- 减少使用通配符与属性选择器;
- 层级扁平,避免过于多层级的选择器嵌套;
- 减少不必要的多余属性;
- 使用简写 CSS 可以节省很多空间;
- 使用 动画属性 实现动画,动画时脱离文档流,开启硬件加速,优先使用 css 动画;
dom 优化:
- 减少访问 dom 的次数,如需多次,将 dom 缓存于变量中;
- 减少重绘与回流
- 使用事件委托,避免大量的事件绑定;
JavaScript代码优化
- 数据读取:
- 通过作用域链 / 原型链 读取变量或方法时,需要更多的耗时,且越长越慢;
- 对象嵌套越深,读取值也越慢;
- 尽量在局部作用域中进行变量缓存;
- 避免嵌套过深的数据结构,数据扁平化 有利于数据的读取和维护;
- 循环: 降低算法时间复杂度
- 条件流程性能: Map / Object > switch > if-else
浏览器网络优化
- 减少 cookie 体积: 能有效减少每次请求的体积和响应时间;
- 去除不必要的 cookie;
- 压缩 cookie 大小;
- 设置 domain 与 过期时间;
文件加载优化
引入位置:
css 文件`<head>`中引入, js 文件`<body>`底部引入;
影响首屏的,优先级很高的 js 也可以头部引入,甚至内联;
减少请求 (http 1.0 - 1.1):
合并请求,正确设置 http 缓存;
减少文件体积:
- 删除多余代码 :
- tree-shaking
- UglifyJs
- code-spliting
- 混淆 / 压缩代码,开启 gzip 压缩;
- 多份编译文件按条件引入 :
- 针对现代浏览器直接给 ES6 文件,只针对低端浏览器引用编译后的 ES5 文件;
- 可以利用
<script type="module"> / <script type="module">
进行条件引入用
- 动态 polyfill,只针对不支持的浏览器引入 polyfill;
图片优化:
- 小图片合成 雪碧图,低于 5K 的图片可以转换成 base64 内嵌;
- 合适场景下,使用 iconfont 或者 svg;
使用缓存:
- 浏览器缓存: 通过设置请求的过期时间,合理运用浏览器缓存;
- CDN缓存: 静态文件合理使用 CDN 缓存技术;
- HTML 放于自己的服务器上;
- 打包后的图片 / js / css 等资源上传到 CDN 上,文件带上 hash 值;
- 由于浏览器对单个域名请求的限制,可以将资源放在多个不同域的 CDN 上,可以绕开该限制;
- 服务器缓存: 将不变的数据、页面缓存到 内存 或 远程存储(redis等) 上;
- 数据缓存: 通过各种存储将不常变的数据进行缓存,缩短数据的获取时间;
webpack性能优化
webpack原理:
通过分析模块之间的依赖,然后通过生态中的各种 Loader 和 Plugin 对代码进行预编译和打包。最终将所有模块打包成一份或者多份代码包 (bundler)。实质上,Webpack 仅仅提供了 打包功能 和一套 文件处理机制。loader基于node的环境,拥有比较高的权限。loader对 Webpack 传入的字符串进行按需修改,通常是需要将代码进行分析,构建 AST (抽象语法树), 遍历进行定向的修改后,再重新生成新的代码字符串。Webpack 会按顺序链式调用每个 Loader,每个loader也只做一件事,输入与输出均为字符串,各个 Loader 完全独立,即插即用。
常用 Loader:
- file-loader: 加载文件资源,如 字体 / 图片 等,具有移动/复制/命名等功能;
- url-loader: 通常用于加载图片,可以将小图片直接转换为 Date Url,减少请求;
- babel-loader: 加载 js / jsx 文件, 将 ES6 / ES7 代码转换成 ES5,抹平兼容性问题;
- ts-loader: 加载 ts / tsx 文件,编译 TypeScript;
- style-loader: 将 css 代码以
<style>
标签的形式插入到 html 中; - css-loader: 分析
@import
和url()
,引用 css 文件与对应的资源; - less-loader / sass-loader: css预处理器,在 css 中新增了许多语法,提高了开发效率;
常用 Plugin:
- UglifyJsPlugin: 压缩、混淆代码;
- CommonsChunkPlugin: 代码分割;
- ProvidePlugin: 自动加载模块;
- html-webpack-plugin: 加载 html 文件,并引入 css / js 文件;
- extract-text-webpack-plugin / mini-css-extract-plugin: 抽离样式,生成 css 文件;
- DefinePlugin: 定义全局变量;
- optimize-css-assets-webpack-plugin: CSS 代码去重;
- webpack-bundle-analyzer: 代码分析;
- compression-webpack-plugin: 使用 gzip 压缩 js 和 css;
- happypack: 使用多进程,加速代码构建;
- EnvironmentPlugin: 定义环境变量
Loader和Plugin的不同
- 不同的作用
- Loader直译为”加载器”。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
- Plugin直译为”插件”。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
- 不同的用法
- Loader在module.rules中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
- Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传
webpack打包的文件名为啥是_hash.js的方式:
- 文件名?_h=hash 的方式和上面的区别是啥,
- 静态资源在cdn上,先部署模板html,还是先部署静态资源
webpack性能优化
1. 缓存
在一些性能开销较大的 loader
之前添加 cache-loader
,将loader
的编译结果缓存中磁盘中。再次构建如果文件没有发生变化则会 直接拉取缓存。如果只给 babel-loader
配置 cache
的话,也可以不使用cache-loader,给 babel-loader增加选项 cacheDirectory
。
通过uglifyjs-webpack-plugin
这个插件也可以解决缓存问题。
缓存的原理就是更快读写的存储介质+减少IO+减少CPU计算=性能优化。而性能优化的第一定律就是:优先考虑使用缓存。
缓存的主要手段有:浏览器缓存、CDN、反向代理、本地缓存、分布式缓存、数据库缓存。
2. 摇树优化 (Tree-shaking),
通过 ES6 的 import/export
来检查未引用代码,以及 sideEffects
来标记无副作用代码,最后用 UglifyJSPlugin
来做 Tree Shaking
,从而删除冗余代码。但是具有副作用的函数无法被 tree-shaking
3. code-spliting:代码分割 ,按需加载
代码分割是指:将脚本中无需立即调用的代码在代码构建时转变为异步加载的过程。
在 Webpack 构建时,会避免加载已声明要异步加载的代码,异步代码在 Webpack 中使用 SplitChunksPlugin 拆分出一个文件,。当代 码实际调用时被加载至页面。
代码分割技术的核心是 异步加载资源。
在 Vue 中,可以直接使用 import()
关键字做到这一点,而在 React 中,需要使用 react-loadable
去完成同样的事。
4. 静态资源分离
通过 `DllPlugin` 或者 `Externals` 进行静态依赖包的分离。由于 CommonsChunkPlugin 每次构建会重新构建一次 vendor,所以出于效率考虑,使用 `DllPlugin` 将第三方库单独打包到一个文件 中,只有依赖自身发生版本变化时才会重新打包。
5. 打包资源的压缩,多进程压缩
_打包资源的压缩_:
- JS 压缩:
UglifyjsWebpackPlugin
- HTML 压缩:
HtmlWebpackPlugin
- CSS 压缩:
MiniCssExtractPlugin
- 图片压缩:
image-webpack-loader
Gzip 压缩:不包括图片
多进程压缩:
因为自带的
UglifyjsWebpackPlugin
压缩插件是单线程运行的,而TerserWebpackPlugin
可以并发运行压缩功能(多进程)。所以通 过TerserWebpackPlugin
代替自带的UglifyjsWebpackPlugin
插件。
6. Scope Hoisting作用域提升
Webpack 会把引入的 js 文件 “提升到” 它的引入者顶部。作用域提升可以让 Webpack 打包出来的 代码文件更小,运行速度更快。
Scope Hoisting
的实现原理其实很简单:分析出模块之间的依赖关系,尽可能将打散的模块合并到一个函数中,前提是不能造成代码冗余。因此只有那些被引用了一次的模块才能被合并。
SSR服务端渲染
渲染过程在服务器端完成,最终的渲染结果 HTML 页面通过 HTTP 协议发送给客户端,又被认为是‘同构’或‘通用’,如果项目中有大量的detail页面,相互特别频繁,建议选择服务端渲染。
Vue的Nuxt.js和React的next.js都是服务端渲染的方法。