啥是防抖,啥是节流
本文的面向对象的不是食堂阿姨的手,也不是新时代钱包里掏不出几个钢镚的平躺人,通过在线预览中的画板的应用,引用出javascript的常见的性能优化场景,同时叙述防抖和节流的区别。
场景引入
下面给大家展示一下左下方画板是如何在预览中使用,(永中ppt在线h5画板示例演示),大家可以思考下画板该怎么呼出和消失。
对上述情况进行拆分一下,正常情况老师们在讲解时候没有操作,预览中应该是无任何操作的按钮:
当有交互性的操作出现,呼出画板,假如通过鼠标的mousemove事件来监听,一但监听到事件,立刻设置画板元素出现。这样老师们就可以进行交互性操作:
那么问题来了,老师想等一段时间后,画板自动消失,听上去不就是setTimeout(隐藏画板,隐藏时间),假设隐藏时间是10s,你在第5秒的时候又移动了鼠标,那么画板是在5s后消失还是存在呢,按照正常的想法,只要移动鼠标,那么画板存在的时间就应该顺延10s,所以最终执行隐藏画板只有一次,也就是哪怕你二十四小时不停的移动鼠标,最终执行隐藏画板的操作只有一次,这就是防抖的一种应用。
防抖
由上面的案例可以引出防抖的概念:就是指触发事件后在n秒内函数只能执行一次,如果在n秒内又触发了这个事情的话,则会重新计算函数执行时间。
附上比较经典的防抖函数:
let content = document.getElementById('cont')
content.onmousemove = debounce(move,1000);
function move() {
console.log('鼠标move')
}
function debounce(func, time) {
let timeout;
return function () {
console.log(this)
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args)
}, time);
}
}
展示出来的效果如下:
对于初学者,有几点需要掌握下,function里面的this指的是什么,还有apply的作用是什么,以及timeout变量充当什么角色,please think about,and the answer is behind.
- this指向就是谁调用的,譬如上面就是cont的dom元素,在上图控制台红色箭头中就可以清晰的看除
- apply就是改变this的指向并且调用这个函数
- 闭包
节流
和防抖不同的是,节流是指在n秒中只执行一次函数,并不像防抖可能很久都不执行一次函数,节流只是为了稀释函数的执行频率。
附上比较经典的节流函数:
let content = document.getElementById('cont')
content.onmousemove = throttle(move,1000);
function move() {
console.log('鼠标move')
}
function throttle(func, time) {
let previous = 0;
return function() {
let now = Date.now();
let context = this;
let args = arguments;
if (now - previous > time) {
func.apply(context, args);
previous = now;
}
}
}
那么效果自然就是鼠标move的时候定时打印出鼠标move
,那么我在这里提出两个问题:
- 如果鼠标离开cont元素,间隔两秒再移动到元素上,控制台会不会立即打印出
鼠标move
? - 上述代码如果不移动,会不会间隔1s打印出
鼠标move
,如果不行,怎么修改代码?
diss diss diss
不能裤子脱一半,上面的问题还是说一下:
- 会,now - previous > 1,所以会立即执行move函数。
2. 不会打印,怎么去实现,直接上代码(当然这个有点取巧了,哈哈,你还要考虑消除setTimeIntervel定时器,上面是时间戳方法,下面的例子使用settimeout去写的,这个是从度娘上参考的,有兴趣可以多研究研究)。
let content = document.getElementById('cont')
content.onmousemove = setTimeIntervel(throttle(move,1000),1000);
function move() {
console.log('鼠标move')
}
function throttle(func, wait) {
let timeout;
return function() {
let context = this;
let args = arguments;
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
总结
简而言之,防抖可能你一辈只执行一次,但是节流会按照固定频率执行,以上防抖和节流的函数其实就跟某些算法题一样,不用刻意去记住,但是要理解里面的this指向,闭包等相关的基础概念即可,希望大家有所收获,thanks for your reading。