这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战
防抖
(一) 什么是防抖
防抖就是触发函数行为之后在一定时间内 只能执行一次,如果在时间内又一次触发,会重新计算函数的执行时间
(二) 防抖的作用
如果一个函数被频繁的触发执行,会消耗大量的内存,影响性能,有可能会造成浏览器卡顿,甚至直接卡死的状况 ,使用防抖处理之后会避免这种情况的出现
(三) 如何实现
可以封装一个防抖的函数,来限制这些函数的触发执行时间 ,防抖可以根据不同业务需求判断是否需要立即执行或非立即执行,该函数接收三个参数,函数,延迟时间,是否立即执行,他会返回一个处理好的新函数
(四) 应用场景
input搜索框的模糊查询,用户在不断输入值的时候,使用防抖可以节约请求资源
文本编辑器实时保存,当无任何操作更改的一秒后进行保存
(五) 代码实现
/**
@desc 防抖函数
@param fun 函数
@param time 延迟时间
@immediate 是否立即执行
*/
const debounce = (fun,time,immediate) => {
let timeout; //定义一个变量存储延时器函数返回的id
return function(){
let args = arguments; //获取参数
let context = this; // 获取this
if( timeout ) clearTimeout(timeout) //判断条件清除定时器函数
if( immediate ){ //是否立即执行
var callNow = !timeout
timeout = setTimeout(()=> {
timeout = null
},time)
if(callNow) fun.apply(context,args)
}else{
timeout = setTimeout(function(){
fun.apply(context,args)
},time)
}
}
}
const newDebounce = debounce('要限制的函数',延迟时间,是否立即执行);
newDebounce()
(六) 防抖函数里面的疑问点
-
这句话的作用是什么: if ( timeout ) clearTimeout ( timeout ) (代码第13行)
疑问解答: 每次执行定时器的时候,都会返回该定时器对应的 id 整数类型的标识,多次调用时就会生成多个定时器,为了防止定时器之间的影响,就可以通过 clearTimeout 方法通过传入 对应 的 id 来清除对应的定时器
-
为什么定义这个变量: var callNow = !timeout (代码第15行)
疑问解答: 为了给fun函数定义一个执行条件,既然 immediate 为true 立即执行了,那么fun的执行条件就必须为真,恰巧 timeout 第一次执行的时候是 undefined 去反就为 true
-
为什么在 setTimeout 里面要给 timeout 重新复制为 null: timeout = null (代码第17行)
疑问解答: 因为setTimeout 里面的回调函数是异步任务,会在最后执行,所以最后要给 timeout 重新赋值为null ,为了下次防抖函数能正常调用
-
防抖函数里面的参数 immediate 的作用有无该参数的区别: (代码第8行)
疑问解答: 当 immediate 为true时会立即执行 fun函数 当immediate 为false或者不传参数的时候,他会依据设定的 延迟时间 time 为基准,等延迟时间结束之后才会执行fun函数
节流
(一) 什么是节流
节流是指连续触发事件执行函数,不会一起执行,而是在单位时间内只执行一次
(二) 节流的作用
节流可以在触发函数行为的频率较高的时候加以限制,只让函数行为触发一次,从而优化函数被多次调用导致的一系列性能和用户体验的问题
(三) 如何实现
封装一个节流的处理函数,节流也是返回的是一个新的函数。
(四) 应用场景
鼠标的移动事件,导致频率非常高,用节流的方式之后单位时间内只触发一次
windown触发resize的时候,不断调整窗口的大小进行触发,用节流只会触发一次
(五) 代码实现
/**
@desc 节流函数
@param fun 函数
@param time 延迟时间
@param type 类型 1是使用时间戳限制 2是使用定时器进行限制
*/
const throttle = (fun,time,type=2) => { // 可以通过type判断使用哪一种节流方式,可以默认是定时器版本
if(type === 1){
nowTime = 0 // 默认第一次触发为0
}else{
timeout = null
}
return function(){
let context = this;
let args = arguments; // 获取this和参数
if(type === 1){ // 依据类型判断执行那种节流方式
let now = Date.now() //获取当前时间戳
if(now - nowTime > time){ //判断触发的频率
fun.apply(context,args)
nowTime = now // 重新赋值以便下次调用
}
} else {
if(!timeout){
timeout = setTimeout(()=>{
timeout = null;
fun.apply(context,args)
},time)
}
}
}
}
const newThrottle = throttle(‘要限制处理的函数方法’,延迟时间,节流的方式);
newThrottle();
(六) 节流函数里面的疑问点
-
节流函数立面的 type为1 和 type 为 2时候 区别在哪: (代码第8行)
疑问解答: 当 type 为1 的时候 是使用以时间戳为判断条件从而执行fun 函数, type为1 会立即执行 fun函数 当 type 为2 的时候 是使用定时器执行fun 函数,type 为2的时候,会等到 time延迟时间结束之后再执行
防抖和节流的区别
- 节流:当type 为 1 的时候,只有当前时间大于上一次的执行时间才执行,当type 为2 时,以有无定时器返回的 id 标识和 定时器的延迟时间为条件判断是否执行的
- 防抖:当immediate 为true 时候 会立即执行,以有无生成定时器返回的id为判断条件,成立则执行,当immediate为false时候,以定时器的延迟时间为条件执行的
- 防抖是通过setTimeout 在一定时间间隔内将多次触发合并成一次触发,节流则是,单位时间内控制触发的频率,单位时间内只执行一次