防抖(debouncing)节流(throttling)
- 防抖:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。(最后一次)
- 节流:在事件被触发n秒后,保证n秒内只执行一次,如果在n秒内被多次触发,只会执行一次。(只一次)
防抖 (debouncing)
防抖:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
应用场景
- 搜索框输入查询
- 窗口大小resize
- 按钮提交
js
function debounce(fn, delay) {
let timer = null;
return function () {
const context = this;
const args = arguments;
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
};
}
举个简单的例子:在搜索框中输入内容,如果用户在300ms内继续输入,则重新计时,直到用户停止输入300ms后,才会触发搜索事件。
js
const input = document.getElementById('input');
input.addEventListener('input', debounce(function () {
console.log(this.value);
}, 300));
手写防抖
手写防抖的实现思路:
- 使用闭包保存定时器
- 返回一个函数,该函数在执行时会清除定时器,并重新设置定时器
- 在定时器到期后执行传入的函数
js
<input type="text" id="search" placeholder="Search...">
<div id="result"></div>
<script>
const searchInput = document.getElementById('search');
const resultDiv = document.getElementById('result');
const fetchResults = debounce(function(query) {
// 模拟 API 请求
resultDiv.innerText = `Searching for: ${query}`;
}, 300);
searchInput.addEventListener('input', (event) => {
fetchResults(event.target.value);
});
</script>
loadash防抖
js
import _ from 'lodash';
const searchInput = document.getElementById('search');
const resultDiv = document.getElementById('result');
const fetchResults = _.debounce(function(query) {
// 模拟 API 请求
resultDiv.innerText = `Searching for: ${query}`;
}, 300);
searchInput.addEventListener('input', (event) => {
fetchResults(event.target.value);
});
节流(throttling)
节流:规定在一个单位时间内,只能触发一次函数。如果在这个单位时间内多次触发,只有一次生效。
应用场景
- 滚动加载更多
- 页面缩放
- 鼠标移动
js
function debounce(fn, delay) {
let timer = null;
return function () {
const context = this;
const args = arguments;
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
};
}
手写节流函数
js
function throttle(fn, delay) {
let timer = null;
return function () {
const context = this;
const args = arguments;
if (!timer) {
timer = setTimeout(() => {
fn.apply(context, args);
timer = null;
}, delay);
}
};
}
loadash节流
js
import _ from 'lodash';
const searchInput = document.getElementById('search');
const resultDiv = document.getElementById('result');
const fetchResults = _.throttle(function(query) {
// 模拟 API 请求
resultDiv.innerText = `Searching for: ${query}`;
}, 300);
searchInput.addEventListener('input', (event) => {
fetchResults(event.target.value);
});
实际案列和应用
js
<script>
const scrollMessage = document.getElementById('scrollMessage');
// 使用 Lodash 的 throttle 函数
const handleScroll = _.throttle(() => {
const time = new Date().toLocaleTimeString();
scrollMessage.innerText = `Scrolled at: ${time}`;
}, 500); // 每 500 毫秒执行一次
window.addEventListener('scroll', handleScroll);
</script>