最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 细谈js-防抖、节流

    正文概述 掘金(张轩溥~)   2021-03-04   481

    应用场景

    防抖和节流是针对高频触发而出现的控制触发频率的解决方案(属于性能优化方案)。

    如: 如鼠标移动事件onmousemove, 滚动滚动条事件onscroll,窗口大小改变事件onresize,监听输入框oninput事件。。。。

    防抖(debounce)

    我先来说一个常见的场景:input输入框远程搜索功能,这里则需要监听oninput事件触发后请求接口。 这时候会出现一个问题,用户输入搜索内容是一个字一个输入的,只要input框内容改变就请求一次接口。其实只有最后一次输入的内容才是用户想要搜索的,这导致了服务器资源的浪费

    细谈js-防抖、节流

    这时候就进行改造,目标为:用户输入过程中不触发请求,停止输入400毫秒后再触发。 这时候就用到了防抖(debounce)

    细谈js-防抖、节流

    版本1(延迟执行): 周期内有新事件触发,清除旧定时器,重置新定时器。

    	
    // 策略是当事件被触发时,设定一个周期延迟执行动作,若期间又被触发,则重新设定周期,直到周期结束,执行动作。
    var debounce = (fn, wait) => {
    	let timer, // 定时器id
        	timeStamp=0, // 最近一次执行时间
    	context,// 执行上下文
        	args;
        
    	let run = ()=>{
    		timer= setTimeout(()=>{
    			fn.apply(context,args);
    		},wait);
    	}
    	let clean = () => {
    		clearTimeout(timer);
    	}
     
    	return function(){
    		context=this;
    		args=arguments;
    		let now = (new Date()).getTime();
     		// 将当前时间与上次执行时间差 与设置的间隔时间比较
    		if(now-timeStamp < wait){
    			console.log('重置',now);
    			clean();  // 清除定时器
    			run();    // 从当前时间重置新的计时器
    		}else{
    			console.log('set',now);
    			run();    // 上次计时器已经执行,设置一个新的计时器
    		}
            // 记录最近一次执行时间
    		timeStamp=now;
    	}
    }
    
    // 使用
    document.getElementById('inp').addEventListener(
    'input', 
      // 执行debounce函数 返回触发执行函数 形成闭包
      debounce(function() {
        console.log(this.value)
      }, 400)
    );
    

    看效果

    细谈js-防抖、节流

    版本2: 周期内有新事件触发,记录最近触发时间,当前周期结束后判断当前周期内是否有触发,如有则设置延时器,以此类推,直到周期结束后判断当前周期内没有触发则执行动作。(此版本不会清除定时器)

    var debounce = (fn, wait) => {
    	let timer, startTimeStamp=0;
    	let context, args;
     
    	let run = (timerInterval)=>{
    		timer= setTimeout(()=>{
    			let now = (new Date()).getTime();
    			let interval=now-startTimeStamp
    			if(interval<timerInterval){ // 判断当前周期内是否被触发
    				console.log('debounce reset',timerInterval-interval);
    				startTimeStamp=now;
    				run(wait-interval);  // 重置定时器的剩余时间
    			}else{
                	// 周期内无触发 执行动作
    				fn.apply(context,args);
    				clearTimeout(timer);
    				timer=null;
    			}
    			
    		},timerInterval);
    	}
     
    	return function(){
    		context=this;
    		args=arguments;
    		let now = (new Date()).getTime();
    		startTimeStamp=now; // 记录最近一次触发时间
     
    		if(!timer){
    			console.log('debounce set',wait);
    			run(wait);    // 上次计时器已经执行,设置一个新的计时器
    		}
    		
    	}
     
    }
    

    版本3(前缘执行): 在版本二基础上添加是否立即执行选项

    当事件快速连续不断触发时,动作只会执行一次,前缘debounce,是在周期开始时执行。

    细谈js-防抖、节流

    var debounce = (fn, wait, immediate=false) => {
    	let timer, startTimeStamp=0;
    	let context, args;
     
    	let run = (timerInterval)=>{
    		timer= setTimeout(()=>{
    			let now = (new Date()).getTime();
    			let interval=now-startTimeStamp
    			if(interval<timerInterval){ // 定时器开始时间被重置,所以interval小于timerInterval
    				console.log('debounce reset',timerInterval-interval);
    				startTimeStamp=now;
    				run(wait-interval);  // 重置定时器的剩余时间
    			}else{
    				if(!immediate){
    					fn.apply(context,args);
    				}
    				clearTimeout(timer);
    				timer=null;
    			}
    			
    		},timerInterval);
    	}
     
    	return function(){
    		context=this;
    		args=arguments;
    		let now = (new Date()).getTime();
    		startTimeStamp=now; // 记录最近一次触发时间
     
    		if(!timer){
    			console.log('debounce set',wait);
                		// 立即执行
    			if(immediate) {
    				fn.apply(context,args);
    			}
    			run(wait);    // 上次计时器已经执行,设置一个新的计时器
    		}
    		
    	}
     
    }
    

    节流(throttling)

    在周期内只执行一次,如有新的事件触发不执行。周期结束后又有事件触发,开始新的周期。节流策略也分前缘和延迟两种。

    延迟:throttling

    细谈js-防抖、节流

    举个栗子:监听浏览器滚动条滚动事件

    // 代码如下 触发滚动事件打印滚动条位置
    onscroll = function() {
    	console.log(this.scrollY)
    }
    

    这时会出现个情况 触发频率非常高,我就按了一下下箭头触发了九次。 细谈js-防抖、节流

    如果处理逻辑发杂的话就对浏览器性能造成了很大负担,这时候节流就登场了。

    // 定时器期间,触发不执行,只在定时器结束后执行
    var throttling = (fn, wait) => {
    	let timer;
    	let context, args;
     
    	let run = () => {
    		timer=setTimeout(()=>{
            		// 周期结束后执行
    			fn.apply(context,args);
    			clearTimeout(timer);
    			timer=null;
    		},wait);
    	}
     
    	return function () {
    		context=this;
    		args=arguments;
    		if(!timer){
    			console.log("周期开始");
    			run();
    		}else{
    			console.log("被节流");
    		}
    	}
     
    }
    
    // 使用 
    onscroll = throttling(function() {console.log(this.scrollY)},200)
    

    细谈js-防抖、节流

    前缘throttling

    细谈js-防抖、节流

    // 上个版本基础上添加前缘
    
    var throttling = (fn, wait, immediate=false) => {
    	let timer, timeStamp=0;
    	let context, args;
     
    	let run = () => {
    		timer=setTimeout(()=>{
            		// 周期结束后执行
    			if(!immediate){
    				fn.apply(context,args);
    			}
    			clearTimeout(timer);
    			timer=null;
    		},wait);
    	}
     
    	return function () {
    		context=this;
    		args=arguments;
    		if(!timer){
    			console.log("周期开始");
                		// 前缘执行
    			if(immediate){
    				fn.apply(context,args);
    			}
    			run();
    		}else{
    			console.log("被节流");
    		}
    	}
     
    }
    
    

    起源地下载网 » 细谈js-防抖、节流

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元