防抖和节流的区别
防抖:在频繁触发的操作中,每次点击重置计时。 节流:在频繁触发的操作中,依然按照给定的时间去触发,降低触发的频率。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="submit">点我打印数据</button>
</body>
<script>
let btn = document.querySelector('#submit');
function handle(ev) {
console.log('ok', ev, this);
}
btn.onclick = handle;
</script>
</html>
点击按钮输出如下
// ok MouseEvent {...} <button id="submit">点我打印数据</button>
防抖的实现
注意修正 event 对象 和 this 哦~
/* debounce: 函数防抖
* @params
* func: 最终要执行的任务代码
* wait: 多久操作一次算是频繁触发「默认值:500ms」
* immediate: 刚开始就触发 「默认值:false,结束时触发」
* @return
* operate 处理函数
*/
const clearTimer = function(timer) {
if (timer) {
clearTimeout(timer);
timer = null;
}
return null;
}
const debounce = function (func, wait, immediate) {
if (typeof func !== 'function') {
throw new TypeError('func must be an function!');
}
// 如果第二个参数传的是个布尔 赋值给第三个参数
if (typeof wait === 'boolean') immediate = wait;
if (typeof wait !== 'number') wait = 500;
if (typeof immediate !== 'boolean') immediate = false;
let timer = null;
return function oprate(...params) {
// 首次调用「或定时器结束重置为首次调用」 且 立即执行
let nowRun = !timer && immediate;
// 如果定时器存在 再次触发 清掉计时 重新计算
timer = clearTimer(timer);
timer = setTimeout(() => {
// 首次点击就调用的 不执行该方法
!nowRun && func.call(this, ...params); // 修正 event 对象
timer = clearTimer(timer); // 清空,为了重新触发 nowRun = true
}, wait);
// 定时器不存在(刚开始点击) 立即执行一次
nowRun && func.call(this, ...params);
}
}
// btn.onclick = debounce(handle); // 非立即执行版本
btn.onclick = debounce(handle, true); // 立即执行版本
节流的实现
节流一般不控制立即执行,默认就是立即执行一次。
/* debounce: 函数节流
* @params
* func: 最终要执行的任务代码
* wait: 触发频率
* @return
* operate 处理函数
*/
const clearTimer = function(timer) {
if (timer) {
clearTimeout(timer);
timer = null;
}
return null;
}
const throttle = function(func, wait) {
if (typeof func !== 'function') {
throw new TypeError('func must be an function!');
}
if (typeof wait !== 'number') wait = 500;
let timer = null;
let prevTime = 0; // 上次触发时间
return function oprate(...params) {
let now = +new Date();
let nextRunTime = wait - (now - prevTime); // 下次执行时间
if (nextRunTime <= 0) {
// 两次间隔时间超过 500ms 第一次是 +new Date() - 0
// 立即执行
func.call(this, ...params);
prevTime = +new Date();
clearTimer(timer);
} else if (!timer) {
// 没设置过定时器等待(上一轮执行过了),则我们设置一个去等待即可
timer = setTimeout(() => {
func.call(this, ...params);
prevTime = +new Date();
clearTimer(timer);
}, nextRunTime);
}
}
}
btn.onclick = throttle(handle, 1000);