一、防抖
1、应用场景: 搜索联想 - 应用防抖
二、节流
三、UnderScore库实现 防抖 节流
<!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>
<input type="text" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.13.4/underscore-min.js"></script>
<script>
const inputEL = document.querySelector("input");
let counter = 0;
const inputChange = function () {
console.log(`发送了第${++counter}网络请求`);
};
inputEL.oninput = _.throttle(inputChange, 2000);
</script>
</body>
</html>
四、自己实现 防抖
1、版本1:debounce基本实现
function debounce(fn, delay) {
let timer = null;
const _debounce = function (...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
return _debounce;
}
index.html
<!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>
<input type="text" />
<script src="./1.debounce基本实现.js"></script>
<script>
const inputEL = document.querySelector("input");
let counter = 0;
const inputChange = function (event) {
console.log(`发送了第${++counter}网络请求`, this, event);
};
inputEL.oninput = debounce(inputChange, 500);
</script>
</body>
</html>
2、版本2:debounce立即执行 - (希望第一次立即执行)
function debounce(fn, delay, immediate = false) {
let timer = null;
let isInvoke = false;
const _debounce = function (...args) {
if (timer) clearTimeout(timer);
if (immediate && !isInvoke) {
fn.apply(this, args);
isInvoke = true;
} else {
timer = setTimeout(() => {
fn.apply(this, args);
isInvoke = false;
}, delay);
}
};
return _debounce;
}
3、版本3:debounce取消功能
function debounce(fn, delay, immediate = false) {
let timer = null;
let isInvoke = false;
const _debounce = function (...args) {
if (timer) clearTimeout(timer);
if (immediate && !isInvoke) {
fn.apply(this, args);
isInvoke = true;
} else {
timer = setTimeout(() => {
fn.apply(this, args);
isInvoke = false;
timer = null;
}, delay);
}
};
_debounce.cancel = function () {
if (timer) clearTimeout(timer);
timer = null;
isInvoke = false;
};
return _debounce;
}
<!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>
<input type="text" />
<button id="cancel">取消</button>
<script src="./3.debounce-取消功能.js"></script>
<script>
const inputEL = document.querySelector("input");
let counter = 0;
const inputChange = function (event) {
console.log(`发送了第${++counter}网络请求`, this, event);
};
const debounceChange = debounce(inputChange, 500, true);
inputEL.oninput = debounceChange;
const cancelBtn = document.querySelector("#cancel");
cancelBtn.onclick = () => {
debounceChange.cancel();
};
</script>
</body>
</html>
4、版本4:debounce函数返回值
function debounce(fn, delay, immediate = false, resultCallback) {
let timer = null;
let isInvoke = false;
const _debounce = function (...args) {
if (timer) clearTimeout(timer);
if (immediate && !isInvoke) {
const result = fn.apply(this, args);
if (resultCallback) resultCallback(result);
isInvoke = true;
} else {
timer = setTimeout(() => {
const result = fn.apply(this, args);
if (resultCallback) resultCallback(result);
isInvoke = false;
timer = null;
}, delay);
}
};
_debounce.cancel = function () {
if (timer) clearTimeout(timer);
timer = null;
isInvoke = false;
};
return _debounce;
}
<!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>
<input type="text" />
<button id="cancel">取消</button>
<script src="./4.debounce-函数返回值.js"></script>
<script>
const inputEL = document.querySelector("input");
let counter = 0;
const inputChange = function (event) {
console.log(`发送了第${++counter}网络请求`, this, event);
return "aaa";
};
const debounceChange = debounce(inputChange, 500, false, (res) => {
console.log("拿到真正函数的返回值", res);
});
inputEL.oninput = debounceChange;
const cancelBtn = document.querySelector("#cancel");
cancelBtn.onclick = () => {
debounceChange.cancel();
};
</script>
</body>
</html>
五、自己实现 节流
1、版本1: throttle 基本实现
function throttle(fn, interval) {
let lastTime = 0;
const _throttle = function () {
let nowTime = new Date().getTime();
const remainTime = interval - (nowTime - lastTime);
if (remainTime <= 0) {
fn();
lastTime = nowTime;
}
};
return _throttle;
}
<!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>
<input type="text" />
<button id="cancel">取消</button>
<script src="./5.throttle-基本实现.js"></script>
<script>
const inputEL = document.querySelector("input");
let counter = 0;
const inputChange = function (event) {
console.log(`发送了第${++counter}网络请求`, this, event);
};
inputEL.oninput = throttle(inputChange, 2000);
</script>
</body>
</html>
2、版本2: throttle - leading实现
<!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>
<input type="text" />
<button id="cancel">取消</button>
<script src="./7.throttle-training功能实现.js"></script>
<script>
const inputEL = document.querySelector("input");
let counter = 0;
const inputChange = function (event) {
console.log(`发送了第${++counter}网络请求`, this, event);
};
inputEL.oninput = throttle(inputChange, 3000, {
leading: true,
training: true,
});
</script>
</body>
</html>
function throttle(
fn,
interval,
options = {
leading: true,
training: false,
}
) {
const { leading, training } = options;
let lastTime = 0;
const _throttle = function () {
const nowTime = new Date().getTime();
if (!lastTime && !leading) lastTime = nowTime;
const remainTime = interval - (nowTime - lastTime);
if (remainTime <= 0) {
fn();
lastTime = nowTime;
}
};
return _throttle;
}
3、版本3: throttle - training实现
function throttle(
fn,
interval,
options = {
leading: true,
training: false,
}
) {
const { leading, training } = options;
let lastTime = 0;
let timer = null;
const _throttle = function () {
const nowTime = new Date().getTime();
if (!lastTime && !leading) lastTime = nowTime;
const remainTime = interval - (nowTime - lastTime);
if (remainTime <= 0) {
if (timer) {
clearTimeout(timer);
timer = null;
}
fn();
lastTime = nowTime;
return;
}
if (training && !timer) {
timer = setTimeout(() => {
timer = null;
lastTime = !leading ? 0 : new Date().getTime();
fn();
}, remainTime);
}
};
return _throttle;
}
<!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>
<input type="text" />
<button id="cancel">取消</button>
<script src="./7.throttle-training功能实现.js"></script>
<script>
const inputEL = document.querySelector("input");
let counter = 0;
const inputChange = function (event) {
console.log(`发送了第${++counter}网络请求`, this, event);
};
inputEL.oninput = throttle(inputChange, 3000, {
leading: true,
training: true,
});
</script>
</body>
</html>
4、版本4: throttle - this, 取消实现
function throttle(
fn,
interval,
options = {
leading: true,
training: false,
}
) {
const { leading, training } = options;
let lastTime = 0;
let timer = null;
const _throttle = function (...args) {
const nowTime = new Date().getTime();
if (!lastTime && !leading) lastTime = nowTime;
const remainTime = interval - (nowTime - lastTime);
if (remainTime <= 0) {
if (timer) {
clearTimeout(timer);
timer = null;
}
fn.apply(this, args);
lastTime = nowTime;
return;
}
if (training && !timer) {
timer = setTimeout(() => {
timer = null;
lastTime = !leading ? 0 : new Date().getTime();
fn.apply(this, args);
}, remainTime);
}
};
_throttle.cancel = function () {
if (timer) {
clearTimeout(timer);
timer = null;
lastTime = 0;
}
};
return _throttle;
}
<!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>
<input type="text" />
<button id="cancel">取消</button>
<script src="./8.throttle-this功能实现.js"></script>
<script>
const inputEL = document.querySelector("input");
let counter = 0;
const inputChange = function (event) {
console.log(`发送了第${++counter}网络请求`, this, event);
};
const _throttle = throttle(inputChange, 3000, {
leading: true,
training: true,
});
inputEL.oninput = _throttle;
const cancelBtn = document.querySelector("#cancel");
cancel.onclick = () => {
_throttle.cancel();
};
</script>
</body>
</html>
|