# 介绍防抖节流原理,区别以及应用,并用 JavaScript 进行实现
# 上期回顾
# HTTP 缓存策略,及解决的问题
- 强制缓存>协商缓存
- 强制缓存:cache-control > expires 【都不知道版本号】
- 协商缓存: Etag/If-None-Match > Last-Modified/If-Modified-Since Etag 的计算成本,modified 的 1s 多次发布定位不了【只精确到 s】
# 今日解题
# 1,防抖
- 原理:在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发 ,则重新计时。
- 适用场景:
- 按钮提交场景:防止多次提交按钮,只执行最后一次
- 搜索框联想场景:防止联想发送请求,只发送最后一次输入
# 简易版本
function debounce(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
func.apply(context, args);
}, wait);
};
}
# 立即执行版本
立即执行函数,然后等到停止触发 n 秒后,才可以重新触发执行
function debounce(func, wait, immediate) {
let timeout;
return function() {
const context = this;
const arg = arguments;
if (timeout) {
clearTimeout(timeout);
}
if (immediate) {
const callNow = !timeout;
timeout = setTimeout(function() {
timeout = null;
}, wait);
if (callNow) func.apply(context, args);
} else {
timeout = setTimeout(function() {
func.apply(context, args);
}, wait);
}
};
}
// <button id="btn">btn-do-do</button>
// <h1 id="container"></h1>
var count = 1;
var container = document.getElementById("container");
var btn = document.getElementById("btn");
function getUserAction() {
console.log(new Date().valueOf());
container.innerHTML = count++;
}
var a = debounce(getUserAction, 2000, false); // important timeout被初始化
btn.onclick = () => {
a(); // 此时timeout共享
};
# 返回值版本
function debounce(func, wait, immediate) {
let timeout, result;
return function() {
const context = this;
const args = arguments;
if (timeout) {
clearTimeout(timeout);
}
if (immediate) {
const callNow = !timeout;
timeout = setTimeout(function() {
timeout = null;
}, wait);
if (callNow) result = func.apply(context, args);
} else {
timeout = setTimeout(function() {
func.apply(context, args);
}, wait);
}
return result;
};
}
const debounce = (fun, delay = 500) => {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(function() {
fun.apply(this, args);
}, delay);
};
};
# 2,节流
- 原理:规定在一个单位时间内,只能触发一次函数,如果这个单位时间内触发多次函数,只能一次生效。
- 适用场景
- 拖拽场景:固定时间内只执行一次,防止超高频次触发位置变动
- 缩放场景:监控浏览器 resize
# 使用时间戳实现
function throttle(func, wait) {
let context, args;
let previous = 0;
return function() {
let now = +new Date();
context = this;
args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
};
}
# 使用定时器
function throttle(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
if (!timeout) {
timeout = setTimeout(function() {
timeout = null;
func.apply(context, args);
}, wait);
}
};
}
const throttle = (fun, delay = 1000) => {
let flag = true;
return function(...args) {
if (!flag) return;
flag = false;
setTimeout(() => {
fun.apply(this, args);
flag = true;
}, delay);
};
};
# 区别:
节流不管事件触发多频繁保证在一定时间内一定会执行一次函数,而防抖是只在最后一次事件触发后才会执行一次函数。