前端基础学习之函数防抖和节流

要解决的问题

前端开发中,经常绑定一些持续触发的事件或异步执行的事件,例如:
1.select下拉框支持远程查询可选列表(异步请求获取数据作为选项列表)
2.用户注册时,手机号 email等格式验证。
3.鼠标在一块div上moverover时执行某些行为。
4.监听页面滚动执行某些行为。
当类似这些行为,不需要实时的去执行时,可以考虑采用防抖和节流的方式。

防抖和节流都是优化高频率执行js代码的一种手段。

防抖 debounce

防抖多用于频繁的触发一个事件,但只需要保证执行一次即可,之前的触发都可以忽略的场景。如上面示例1 2

立即执行: 触发事件后立即执行函数,开始计时,在n秒内再次触发事件,不执行函数,并且重新计时。n秒后触发事件,立即执行函数,开始计时。(保证立即执行,屏蔽频繁操作[不执行]

/*html*/
<input id="search" placeholder='输出关键字查询匹配列表' />
<ul id="options"></ul>

/*js*/
let list = ['123','12345','1234567','123456789'];
var search = document.getElementById('search');
var options = document.getElementById('options');

let debounce_show = debounce(show, 1000);
search.addEventListener('input', e => {
    options.innerHTML = `<li>正在查询...</li>`;
    let keyword = e.target.value;
    debounce_show(keyword);
})

function show(val) {
    let filterList = list.filter(v => {
        return v.includes(val);
    });
    let filterHtml = '';
    if (filterList.length == 0) {
        filterHtml = `<li>未匹配到数据</li>`;
    } else {
        filterList.forEach(v => {
            filterHtml += `<li>${v}</li>`;
        });
    }
    options.innerHTML = filterHtml;
}

/*
func 需要防抖的函数
wait 防抖时间(秒)
*/
function debounce(func, wait) {
	let timeout = null;
	return function (...args) {
		let context = this;
		if (timeout) {
			clearTimeout(timeout); // 只是取消计时,timeout值没变,typeof timeout === 'number'
		}
		if (!timeout) {
			func.apply(context, args);
		}
		timeout = setTimeout(() => {
			timeout = null;
		}, wait);
	}
}

非立即执行: 触发事件后开始计时,在n秒后执行函数,如果在n秒内再次触发事件,则重新计时,保证等待n秒才执行函数。(延迟执行,频繁操作不断覆盖,保证执行最后的一次

// 修改上面的debounce为:
function debounce(func, wait) {
	let timeout = null;
	return function (...args) {
		let context = this;
		if (timeout) {
			clearTimeout(timeout); // 只是取消计时,timeout值没变,typeof timeout === 'number'
		}
		timeout = setTimeout(() => {
            func.apply(context, args);
			timeout = null;
		}, wait);
	}
}

节流 throttle

节流多用于频繁触发一个事件,但频率不必太高,希望控制频率以减少内存消耗的场景。如上面示例3 4

防抖延迟执行以避免频繁执行不同,节流允许频繁执行,但可以限制触发频率
也就是重复触发事件时,不重新计时,只判断是否允许执行。

节流原理: 设置一个空闲时间n秒,触发事件执行方法后,开始计时,n秒内再次触发事件不执行方法,n秒后触发事件才允许执行。

同样可以定义立即执行非立即执行

/*html*/
<div style="height:4000px;">
    <div id="time" style="position: fixed;"></div>
</div>

/*js*/
let throttle_showTime = throttle(showTime,1000);
document.addEventListener('scroll', e=>{
    console.log('scroll')
    throttle_showTime();
});
function showTime() {
    let now = new Date();
    let time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
    document.getElementById('time').innerText = time;
}
/* 合并版的节流方法
func 需要节流的函数
wait 允许触发的最小间隔(秒)
immediate 是否立即执行
*/
function throttle(func, wait, immediate=true) {
    let timeout = null;
    return function (...args) {
        let context = this;
        if (!timeout) {
            if (immediate) { // 立即执行版本
                func.apply(context, args);
                timeout = setTimeout(() => {
                    timeout = null;
                }, wait);
            } else { // 非立即执行版本
                timeout = setTimeout(() => {
                    func.apply(context, args);
                    timeout = null;
                }, wait);
            }
        }
    }
}

上面代码运行后,在页面中一直滚动,可以根据输出的时间看出执行的频率为1秒1次
也可以用时间戳来实现,具体见参考的文章。

参考:
JavaScript专题之跟着 underscore 学防抖
JavaScript专题之跟着 underscore 学节流

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值