一 懒加载
懒加载的概念
- 懒加载也叫做延迟加载啊、按需加载,可以在网页中对长列表数据或者图片进行延迟加载,是一种较好的网页性能优化的方式。
懒加载的概念懒加载的特点
- 减少无用的资源加载
- 提升用户体验
- 防止加载过多的图片或者数据影响其他资源文件的加载
懒加载于预加载的区别
- 懒加载也叫做预加载,指的是长网页中延迟加载图片的时机,当用户需要访问时,再去加载
- 预加载指的是将所需的资源提前请求加载到本地,这样后面在需要的时候就直接从缓存中拿取
二 回流与重绘
回流
-
当渲染树中部分或者全部元素的尺寸、结构属性发生变化时,浏览器会重新渲染部分或者全部文档的过程就时回流
- 页面的首次渲染
- 浏览器窗口大小发生变化
- 元素的内容发生变化
- 元素的尺寸或者位置发生变化
- 元素的字体大小发生变化
- 激活css伪类
- 查询某些属性或者调用某些方法
- 添加或删除可见的DOMN元素
-
因为浏览器的渲染时基于流式布局的,它的影响范围分为
- 全局范围:从根节点开始,对整个渲染树进行重新布局
- 局部范围:对渲染树的某部分或者一个渲染对象进行重新布局
重绘
- 当页面中某些元素的样式发生变化,但是不会影响其在文档流中的位置时,浏览器就会对元素进行重新绘制,这个过程就是重绘 这些操作会导致重绘:
color、background 相关属性: background-color、background-image等
outline 相关属性: outline-color、outline-width 、text-decoration
border-radius,isibility、 box-shadow
注意: 当触发回流时,一定会触发重绘,但是重绘不一定会引发回流
减少回流与重绘的措施
- 操作DOM时,尽量在低层级的DOM节点进行操作
- 不要使用 table 布局,一个小的改动可能会使整个 table 进行重新布局
- 使用CSS的表达式
- 不要频整操作元素的样式,对于静态页面,可以修改类名,而不是样式
- 使用absolute或者fixed,使元素脱离文档流,这样他们发生变化就不会影响其他元素避免频繁操作DOM,可以创建一个文档片段 documentFragment ,在它上面应用所有DOM操作,最后再把它添加到文档中
- 将元素先设置 display: none ,操作结束后再把它显示出来。因为在display厘性为none的元素上进行的DOM操作不会引发回流和重绘。
- 将DOM的多人读操作(或者写操作) 放在一起,而不是读写操作穿插着写,这得益于浏览器的染队列机制。
浏览器针对页面的回流与重绘,进行了自身的优化一一渲染队列
浏览器会将所有的回流、重绘的操作放在一个队列中,当队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会对队列进行批处理。这样就会让多次的回流、重绘变成一次回流重绘。
上面,将多个读操作(或者写操作)放在一起,就会等所有的读操作进入队列之后执行,这样,原本应该是触发多次回流,变成了只触发一次回流。
三 防抖和节流
节流和防抖的意思
- 函数防抖是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。这可以使用在些点击请求的事件上,避免因为用户的多次点击向后端发送多次请求。
- 函数节流是指规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一人单位时间内某事性被触发多次,只有一次能生效。节流可以使用在 scrol 函数的事件监听上,通过事件节流来降低事件调用的频率。
节流和防抖的实现
// 防抖函数
function db(fn, time) {
let timer = null;
return function(){
let that = this,
arg = arguments;
if(timer){
clearTimeout(timer);
timer=null;
}
timer = setTimeout( ()=>{
fn.apply(that,arg);
},time)
}
}
// 节流函数
function thro( fn, delay){
let date = Date.now();
return function(){
let that = this,
arg = arguments,
nowTime = Date.now();
if(nowTime - date >= delay){
date = Date.now();
return fn.apply(that,arg);
}
}
}
四 webpack优化
webpack打包速度
(1)优化 Loader
对于Loader 来说,影响打包效率首当其冲必 Babel了。因为 Babel 会将代码转为字符串生成 AST,然后对AST 继续进行转变最后再生成新的代码,项目越大,转换代码越多,效率就越低。当然了,这是可以优化的 首先我们优化 Loader 的文件搜索范围
module.exports = {
module: {
rules: [
{
// js 文件才使用
babeltest: /\.js$/,
loader: 'babel-loader',
// 只在 src 文件夹下查找
include: [resolve('src')],
// 不会去查找的路径
exclude: /node_modules/,
// 将 abel 编译过的文件缓存起来,下次只需要编译更改过的代码文件即可,这样可以
// 大幅度加快打包时间
loader: "babel-loader?cacheDirectory=true"
}
]
}
}
(2) HappyPack
受限于 Node 是单线程运行的,所以 Webpack 在打包的过程中也是单线程的,特别是在执行 Lader 的时候,长时间编译的任务很多,这样就会导致等待的情况。
HappyPack 可以将 Loader 的同步执行转换为并行的,这样就能充分利用系统资源来加快打包效率了
module: {
loaders: [
{
test: /\js$/,
include: [resolve('src')],
exclude: /node_modules/,// id 后面的内容对应下面
loader: "happypack/loader?id=happybabel",
}
]
},
plugins: [
new HappyPack({
id: "happybabel",
loaders: ["babel-loader?cacheDirectory"],
// 开启 4 个线程
threads: 4
})
]
(3)DlIPlugin
DlIPlugin 可以将特定的类库提前打包然后引入,这种方式可以极大的减少打包类库的次数,只有当类库更新版本才有需要重新打包,并且也实现了将公共代码抽离成单独文件的优化方案。 DllPlugin 的使用方法如下:
// 单独配置在一个文件中
// webpack.dll.conf.js
const path = require('path')
const webpack = require("webpack")
module.exports = {
entry: {
// 想统一打包的类库
vendor: ['react']
},
output: {
path: path.join(dirname, "dist"),
filename: '[name].dll.js',
library: "[name] -[hash]"
},
plugins: [
new webpack.DllPlugin({
// name 必须和 output.library 一致
name: "[name]-[hash]",// 该属性需要与 DIIReferenceplugin 中一致
context: __dirname,
path: path.join(__dirname, 'dist', "[name]-manifest.json")
})]
}
然后需要执行这个配置文件生成依赖文件,接下来需要使用 DllReferencePlugin 将依赖文件引入项目中
// webpack.conf.js
module.exports = {
// ...省略其他配置
plugins: [
new webpack.DllReferenceplugin({
context: dirname,
// manifest 就是之前打包出来的 json 文件
manifest: require("./dist/vendor-manifest.json")
})]
}
(4) 代码压缩
在webpack3中需要使用 UglifyJS 来压缩代码,但是在webpack4中只需要将 mode 设置为 production 就可以默认开启。
(5) 其他的方法
可以通过一些小的优化点来加快打包速度
- resolve.extensions : 用来表明文件后缀列表,默认查找顺序是 [".js",".json"],如果你的导入文件没有添加后缀就会按照这个顺序查找文件。我们应该尽可能减少后缀列表长度,然后将出现频率高的后缀排在前面
- resolve.alias : 可以通过别名的方式来映射一个路径,能让 Webpack 更快找到路径 3.** module.noParse :** 如果你确定一个文件下没有其他依赖,就可以使用该属性让 Webpack 不扫描该文件这种方式对于大型的类库很有帮助
如何使用 webpack优化前端性能
用webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效
- 压缩代码: 删除多余的代码、注释、简化代码的写法等等方式。可以利用webpack的 UglifyJsPlugin 和 ParallelUglifyPlugin 来压缩JS文件,利用 cssnano (css-loader?minimize) 来压缩css
- 利用CDN加速: 在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用webpack对于output 参数和各loader的 publicPath 参数来修改资源路径
- Tree Shaking: 将代码中永远不会走到的片段删除掉。可以通过在启动webpack时追加参数 --optimize-minimize 来实现
- Code Spliting: 将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利用浏览器缓存提取公共第三方库: SplitChunksplugin 插件来进行公共模块抽取,利用浏览器缓存可以长期缓存这些无需频繁变动的公共代码
如何提高 webpack的构建速度
- 多入口情况下,使用 CommonsChunkPlugin 来提取公共代码
- 利用 DIPlugin 和 DIReferencePluain 预编译资源模块 通过 DlPlugin 来对那些我们引用是绝对不会修改的npm包来进行预编译,再通过 DIIReferencePlugin 将预编译的模块加载进来
- 通过 externals 配置来提取常用库
- 使用 Happypack 实现多线程加速编译
- 使用 Tree-shaking 和 Scope Hoisting 来剔除多余代码
- 使用 webpack-uglify-parallel 来提升 uglifyPlugin 的压缩速度。原理上webpack-uglify-parallel采用了多核并行压缩来提升压缩速度