函数节流:
通俗概念:
降频,如果触发频次太快,需要降低触发次数的频率
为什么要函数节流
前端开发过程中,有-些事件或者函数,会被频繁地触发(短时间按内多次触发),最常 见的例
如,onresize , scroll , mousemove ,mousehover等,这些事件的触发频率很高,不做限制的话,有可
能一秒之内执行几十次、几百次,如果在这些函数内部执行了其他函数,尤其是执行了操作DOM的函
数(浏览器操作DOM是很耗费性能的,因为浏览器会根据真实dom的变化来进行重绘和重排) , 那不仅会造成计算机资源的浪费,还会降低程序运行速度,甚至造成浏览器卡死、崩溃,这种问题显然是致命的。所以就需要用到函数节流来节制一下,给他规定个时间来触发。
代码实现(以一个鼠标移动的案例为例)
window.onload = function(){
var node = document.getElementById("div1")
var i = 0;
function handleMove(){
console.log(i++);
}
node.onmousemove = throttle(handleMove,2000);
}
通过时间戳的方法节流:
第一次立即触发,往后每隔两秒触发一次
function throttle(func,wait){
let prevDate = 0 //记录上次时间
let curDate = Date.now(); //记录当前时间
return function(){
const context = this;
const arg = arguments;
//console.log(this) //指向div
curDate = Date.now();
if(curDate - prevDate >= wait){
//当前触发事件的时间减去上次触发事件的时间大于等于延时的时间,也就是说在指定的时间内是永远都不会
//去执行,因为根本就没有那段的函数啊,执行个桃子啊。
func.apply(context,arg);
prevDate = curDate;
// console.log(this) //指向div
}
}
}
//也可以这样写:两种写法最终的this指向都是div,但是在setTimeout的写法中就不能省略获取this以及
//arguments的步骤,主要原因就是setTimeout中的this指向是window,如果不设置的话,最后在回调的时候
//就获取不到想要获取的目的值。
function throttle(func,wait){
let prevDate = 0 //记录上次时间
let curDate = Date.now(); //记录当前时间
return function(){
curDate = Date.now(); //需要在return里面在记录一下当前的时间
if(curDate - prevDate >= wait){
func();
prevDate = curDate;
}
}
}
通过setTimeout方法:
第一次触发也是在指定时间后执行
function throttle(func,wait){
let timer = 0;
return function(){
const context = this;
const arg = arguments;
if(!timer){
timer = setTimeout(function(){
func.apply(context,arg);
//setTimeout中的this都是指向window的,所以必须强转
clearTimeout(timer);
//这里就是第一次触发的时候在指定时间后执行,执行完毕第一次后关闭延时器,同时将timer设置为空,确保
//加下来的每次都会重新触发延时器,重新从零开始计时,避免因为多次触发事件而导致延时器一直关闭重启关
//闭重启。恰好与函数防抖相反。
timer = null
},wait)
}
}
}
应用场景
1.懒加载、滚动加载、监听滚动条的位置
2.搜索框
3.防止表单重复提交
暂时能想到就这些,不过这并不一定都是这些场景才能应用,只要理解了原理后,想怎么用就怎么用,只要不妨碍程序的正常运行,不造成什么乱七八糟的后果,你随便。
总结
函数节流主要的目的就是降低触发的频率,从而减少页面的重绘和重排,减少浏览器的性能消耗。