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

要解决的问题

前端开发中,经常绑定一些持续触发的事件或异步执行的事件,例如:
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 = `
  • 正在查询...
  • `
    ; 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 = `
  • 未匹配到数据
  • `
    ; } else { filterList.forEach(v => { filterHtml += `
  • ${v}
  • `
    ; }); } 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 学节流

    你可能感兴趣的:(前端基础,javascript)