[TOC] #### 1. 防抖是什么 ---- 防抖: 在事件被触发 n 秒后执行回调,如果在这 n 秒内又被触发,则重新计时 也就是指连续触发事件,但是在设定的一段时间内只执行一次 防抖的应用场景: 输入框连续输入值后,等到最后一次输入完成才触发查询的动作 #### 2. 输入框的防抖处理 ---- ```html <input type="text" id="ipt"> ``` ```javascript function input(e) { request(e.target.value) } function request(data) { console.log('请求参数: ', data); } // 防抖函数 function debounce(fun, delay = 200) { let timeout = null return function (...args) { if (timeout) { clearTimeout(timeout) timeout = null } timeout = setTimeout(() => { fun.apply(this, args) }, delay) } } input = debounce(input, 300) document.getElementById('ipt').oninput = input ``` #### 3. 第三方库实现防抖 ---- 可以通过第三方库来实现防抖操作:lodash、underscore。下面我们采用 underscore ```html <input type="text" class="search"> <script src="https://cdn.bootcdn.net/ajax/libs/underscore.js/1.13.7/underscore-umd-min.js"></script> <script> const search = document.querySelector('.search') let counter = 0 function searchChange() { counter++; console.log(`发送${counter}次网络请求`); } // search.oninput = searchChange // 普通写法 // search.oninput = _.debounce(searchChange, 1000) // 防抖处理 search.oninput = _.throttle(searchChange, 1000) // 节流处理 </script> ``` #### 4. 手写防抖函数 ---- ```html <input type="text" class="search"> <script> const search = document.querySelector('.search') let counter = 0 function searchChange(event) { counter++; console.log(`发送${counter}次网络请求`, this, event); } // search.oninput = searchChange // 普通写法 search.oninput = debounce(searchChange, 1000) // 节流处理 // 防抖处理 function debounce(fn, delay) { // 1. 定义一个定时器,保存上一次的定时器 let timer = null; // 2. 真正执行的函数 return function (...args) { // 取消上一次的定时器 if (timer) { clearTimeout(timer) timer = null; } // 延迟执行 外部传入的真正执行的函数 timer = setTimeout(() => fn.apply(this, args), delay) } } </script> ``` 扩展内容:每次输入内容时,先立即执行一次 ```javascript // 防抖处理(immediate 是否立即执行) function debounce(fn, delay, immediate = false) { // 1. 定义一个定时器,保存上一次的定时器 let timer = null; let isInvoke = false; // 2. 真正执行的函数 return function (...args) { // 取消上一次的定时器 timer && clearTimeout(timer); // 判断是否需要立即执行 if (immediate && !isInvoke) { fn.apply(this, args) isInvoke = true } else { // 延迟执行 外部传入的真正执行的函数 timer = setTimeout(() => { fn.apply(this, args) isInvoke = false }, delay) } } } ```