版权声明:感谢支持原创 https://blog.csdn.net/lilele0227/article/details/87451710
背景
项目中遇到一个需要实现文字拖动的效果,用mousedown、mousemove、mouseup模拟拖动效果。但是实现的效果并不是很理想,原因是mousemove是一个高频事件,触发的频率非常高,会造成浏览器的性能问题。
场景
高频触发事件,对执行函数进行节流可以节省浏览器资源,以免造成不必要的性能浪费。具体的应用场景有:
- DOM元素实现拖拽功能(mousemove)
- window对象的resize、scroll事件
- 绝地求生中的武器射速(此处不是性能优化)
- 文字输入、自动完成的keyup事件
概念
以吃鸡游戏为例,假设M416的射速不用函数节流,理论上是无数次,分分钟秒杀敌军。而函数节流就是要实现这么一个效果——一定时间内,只能有效触发一次函数,即M416一秒内只能射出X发子弹(射出一次子弹可以理解为有效触发一次函数)。
实现
没有代码的博客都是耍流氓,我们以mousemove事件为例来看看函数节流的威力。
- 未优化代码
<script>
let moveStatus = false;
let startTime, lastTime;
window.onmousedown = function(){
console.log('down');
moveStatus = true;
startTime = new Date();
}
window.onmousemove = function(){
lastTime = new Date() - startTime;
if(moveStatus && lastTime < 1000) {
lastTime = new Date;
console.log('我拖拖拖拖拖!!!');
}
}
window.onmouseup = function(){
console.log('up');
moveStatus = false;
}
</script>
运行的结果如图:
可以看出每秒触发60次左右move事件,拖动的过程会高频触发函数,好比绝地求生的M416,你让它每秒射10000发子弹,枪它受不了啊。为了让枪受得了,我们规定你只能10ms来一发,代码如下:
- 函数节流优化后的代码
<script>
let moveStatus = false;
let startTime, lastTime;
let timer = null;
window.onmousedown = function(){
console.log('down');
moveStatus = true;
startTime = new Date();
}
window.onmousemove = function(){
if(timer) {
return false;
}
timer = setTimeout(() => {
timer = null;
lastTime = new Date() - startTime;
if(moveStatus && lastTime < 1000) {
lastTime = new Date;
console.log('我拖拖拖拖拖!!!');
}
},50)
}
window.onmouseup = function(){
console.log('up');
moveStatus = false;
}
</script>
我们规定每50ms内只能运行一次函数,理论上1秒内可以触发20次,但由于手动操作,鼠标移动速度不可能无限快,会造成部分时间损耗。但这都不是重点,重点是我们已经可以控制move的触发频率了。一秒触发15次左右,相比60次可以大幅度节省浏览器资源。
既然介绍到函数节流,那么函数防抖想必也是要介绍的,下期再介绍吧。