函数防抖与函数节流

本文介绍了函数防抖和节流的概念、原理及应用。函数防抖是在一定时间内动作只执行一次,通过闭包和 setTimeout 实现;函数节流是限制函数在短时间内连续调用。二者可优化函数触发频率过高导致的性能问题,如在滚动、调整大小等 DOM 事件中应用。

函数防抖

概念: 函数防抖(debounce)是指在一定时间内,在动作被连续频繁触发的情况下,动作只会被执行一次,也就是说当调用动作过n毫秒后,才会执行该动作

ES5写法:

            
            // debounce函数用来包裹我们的事件处理方法
            function debounce(fn, delay){
                // 持久化一个定时器
                let timer = null
                
                // 闭包函数可以访问timer
                return function(){
                    // 通过 this 和 arguments 获得函数的作用域和参数
                    let context = this
                    let args = arguments
                    // 如果事件被触发,清除timer并重新开始计时
                    clearTimeout(timer)
                    timer = setTimeout(function() {
                        fn.apply(context, args)
                    }, delay)
                }
            }

            function foo(){
                console.log('You are scrolling!')
            }

            document.addEventListener('scroll', debounce(foo, 50));

复制代码

ES6写法:

 

 

 

 

 

export function debounce(fn, interval = 300) {
    let timer = null;
    return function () {
        clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(this, arguments);
        }, interval);
    };
}

let debounce = (fn, time = 50) => { // 防抖动 控制空闲时间
    let timer;
    return function (...args) {
        let that = this;
        clearTimeout(timer);
        timer = setTimeout(fn.bind(that, ...args), time);
    }
}  

复制代码

 

原理:通过闭包保存一个标记来保存 setTimeout 返回的值,每当用户输入的时候把前一个 setTimeout clear 掉,然后又创建一个新的 setTimeout,这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数了。


 

函数节流

概念: 函数节流,就是让一个函数无法在很短的时间间隔内连续调用,只有当上一次函数执行后过了你规定的时间间隔,才能进行下一次该函数的调用。比如,在让缩放内容的操作在你不断改变窗口大小的时候不会执行,只有你停下来一会儿,才会开始执行。

原理:当我触发一个事件时,先setTimout让这个事件延迟一会再执行,如果在这个时间间隔内又触发了事件,那我们就clear掉原来的定时器,再setTimeout一个新的定时器延迟一会执行,就这样。

案例:这些概念的一个主要用例是某些DOM事件,如滚动和调整大小。例如,如果我们将一个滚动处理程序附加到元素,并将该元素向下滚动到5000px,则可能会看到超过100个事件触发。如果我们的事件处理程序执行一些工作(如重计算和其他DOM操作),我们可能会看到性能问题。如果你可以使执行该处理程序的次数减少,而没有太多的中断,那这些工作是值得的。

一些小例子:

1)等到用户停止调整窗口大小

2)在用户停止打字之前,不要触发ajax事件

4)计算页面的滚动位置,每50ms最多执行一次

5)在应用程序中拖动元素时,请确保良好的性能

 

ES5:

 

 

 

 

 

function throttle(fn, threshold){
	var timeout
	var start = new Date;
	var threshhold = threshhold || 160

	return function () {
		var context = this, 
		args = arguments, 
		curr = new Date() - 0;

		clearTimeout(timeout)//总是干掉事件回调

		if(curr - start >= threshhold){ 
			console.log("now", curr, curr - start)
                        //注意这里相减的结果,都差不多是160左右
			fn.apply(context, args) 
                        //只执行一部分方法,这些方法是在某个时间段内执行一次
			start = curr 
                        //重新开始计算时间
		}else{
			//让方法在脱离事件后也能执行一次
			timeout = setTimeout(function(){
				fn.apply(context, args) 
			}, threshhold);
		}
	}
}
var mousemove = throttle(function(e) {
    console.log(e.pageX, e.pageY)
});

document.querySelector("#panel").addEventListener('mousemove', mousemove); 复制代码

ES6

 

 

 

 

export function throttle(fn, waitTime = 1000){
  let lastTime = null
  return function () {
    let startTime = + new Date()
    if (startTime - lastTime > waitTime || !lastTime) {
      fn()
      lastTime = startTime
   }
 }
}

 let throttle = (fn, delay = 50) => { 
      //节流 控制执行间隔时间 防止频繁触发 scroll resize mousemove
            let stattime = 0;
            return function (...args) {
                let curTime = new Date();
                if (curTime - stattime >= delay) {
                    fn.apply(this, args);
                    stattime = curTime;
                }
 }复制代码

注意:函数节流(throttle)与 函数防抖(debounce)都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。

比如如下的情况:

window对象的resize、scroll事件

拖拽时的mousemove事件

文字输入、自动完成的keyup事件

 

总结:函数防抖实现的核心在于每次都去clear一个延时器,然后每次执行函数的时候,都去clear以前的延时器。只有当你中断事件的时候,才会去执行相应回调。而函数节流的核心是去判断当前时间和开始时间的间隔是否到达了设置的delay值,如果达到了,就执行一次回调。没有则不执行。

 


作者:李赫feixuan
链接:https://juejin.im/post/5b3e2cc8f265da0fab3ff8e2
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值