先看看概念
函数防抖(debounce):
在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时;典型的案例就是输入搜索:输入结束后n秒才进行搜索请求,n秒内又输入的内容,就重新计时。
应用场景:
- search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
- window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="btn">第一次点击按钮立即执行 接下来 防抖</button>
<button id="btn2">终止</button>
</body>
<script>
var btn = document.getElementById('btn');
let b= 2
let f = debounce_2(sayHi,2000,true)
btn.addEventListener('click',()=>{
f(b)
})
btn2.addEventListener('click',()=>{
f.stop()
})
// 防抖(非立即执行)
function debounce_1(fn,wait){
let timer = null;
return function(){
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this,arguments)
},wait)
}
}
// 防抖立即执行
function debounce_2(fn,wait){
let time = null
let flag = true
return function (){
clearTimeout(time)
if(flag){
fn.apply(this,arguments)
flag = false
}
time = setTimeout(()=>{
flag = true
},wait)
}
}
// 防抖自定义第一次是否执行
function debounce_3(fn,wait,isImmediate = true){
let flag = true
let time = null
if(isImmediate){
if(flag){
return function (){
fn.apply(this,arguments)
flag = false
}
}
clearTimeout(time)
time = setTimeout(()=>{
flag = true
},wait)
}
return function (){
clearTimeout(time);
time = setTimeout(() => {
fn.apply(this,arguments)
},wait)
}
}
// 防抖自定义第一次是否执行 且可中断执行
function debounce_4(fn, wait = 500, isImmediate = false) {
// 计时器
let timerId = null;
// flag为真时立即执行
let flag = true;
let resultFunc = null;
if (isImmediate) {
// 立即执行
// 例如:用户在输入框中输入字符,输入第一个字符时,立即执行一次
// 之后,最终间隔超过2秒后,才执行补全查询
resultFunc = function () {
let context = this;
clearTimeout(timerId);
if (flag) {
fn.apply(context, arguments);
flag = false
}
timerId = setTimeout(() => {
flag = true
}, wait)
}
resultFunc.cancel = function () {
// 例如,用户打字很快,然后输入完成后,未达到两秒钟就移动鼠标
// 此时输入框失去焦点,触发取消等待方法,立刻执行补全查询操作并显示结果出来
console.log("立即取消等待")
clearTimeout(timerId);
flag = true;
}
} else {
// 不立即执行
// 例如:用户在输入框中输入字符,最终间隔超过2秒后,才执行补全查询
resultFunc = function () {
let context = this;
clearTimeout(timerId);
timerId = setTimeout(() => {
fn.apply(context, arguments)
}, wait)
}
resultFunc.cancel = function () {
console.log("立即取消等待");
clearTimeout(timerId);
}
}
return resultFunc;
}
function sayHi(b) {
console.log(b)
console.log('防抖')
}
</script>
</html>
函数节流(throttle):
规定在一个单位时间内,只能触发一次函数,如果这个单位时间内触发多次函数,只有一次生效; 典型的案例就是鼠标不断点击触发,规定在n秒内多次点击只有一次生效。
应用场景:
- 鼠标不断点击触发,mousedown(单位时间内只触发一次)
- 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="btn">第一次点击按钮立即执行 接下来 节流</button>
<button id="btn2">终止</button>
</body>
<script>
var btn = document.getElementById('btn');
let b= 2
let f = throttle_4(sayHi,3000)
btn.addEventListener('click',()=>{
f(b)
// throttle_3(sayHi,3000)(b) 不能这么写,因为这相当于每次都重新声明了这个节流函数
})
btn2.addEventListener('click',()=>{
f.stop()
})
//节流(非立即执行)
function throttle_1(fn,wait){
let flag = true;
return function(){
if(flag == true){
flag = false
var timer = setTimeout(() => {
fn.apply(this,arguments)
flag = true
},wait)
}
}
}
//节流(立即执行)
function throttle_2(fn,wait){
var flag = true;
var timer = null;
return function(){
if(flag) {
fn.apply(this,arguments);
flag = false;
timer = setTimeout(() => {
flag = true
},wait)
}
}
}
//节流(自定义是否立即执行)
function throttle_3(fn,wait = 500,isImmediate = false){
let flag = true;
let timer = null;
if(isImmediate){
return function(){
if(flag) {
fn.apply(this,arguments);
flag = false;
timer = setTimeout(() => {
flag = true
},wait)
}
}
}
return function(){
if(flag == true){
flag = false
var timer = setTimeout(() => {
fn.apply(this,arguments)
flag = true
},wait)
}
}
}
//节流(自定义是否立即执行且可以中断)
function throttle_4(fn, wait = 500, isImmediate = false) {
let flag = true;
let timer = null;
let resultFunc = null;
if (isImmediate) {
// 立即执行
resultFunc = function () {
if (flag) {
fn.apply(this, arguments);
flag = false;
timer = setTimeout(() => {
flag = true
}, wait)
}
}
resultFunc.cancel = function () {
console.log("立即取消等待")
clearTimeout(timer)
}
} else {
// 不立即执行
resultFunc = function () {
if (flag == true) {
flag = false
timer = setTimeout(() => {
fn.apply(this, arguments)
flag = true
}, wait)
}
}
resultFunc.cancel = function () {
console.log("立即取消等待")
clearTimeout(timer);
flag = true;
}
}
return resultFunc;
}
function sayHi(b) {
console.log(b)
console.log('节流')
}
</script>
</html>
长风破浪会有时,直挂云帆济沧海