前言
我们在平时开发的时候,会有很多场景会频繁触发事件,比如说搜索框实时发请求,onmousemove, resize, onscroll等等,有些时候,我们并不能或者不想频繁触发事件,咋办呢?这时候就应该用到函数防抖和函数节流了!
一、主体代码
HTML代码
<div id="content" style=""></div>
CSS代码
#content{
height:150px;
line-height:150px;
text-align:center;
color: #fff;
background-color:#ccc;
font-size:80px;
}
JS代码
let num = 1;
let content = document.getElementById('content');
function count() {
content.innerHTML = num++;
};
content.onmousemove = count;
实现效果如下:
二、防抖
设置定时器,短时间内高频率触发只有最后一次触发成功。
1.非立即执行版
触发事件后函数不会立即执行,而是在n秒后执行,如果n秒内又触发了事件,则会重新计算函数执行时间。
// 非立即执行版
function debounce(func, wait) {
let timer;
return function() {
let context = this; // 注意 this 指向
let args = arguments; // arguments中存着e
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args)
}, wait)
}
}
我们是这样使用的:
content.onmousemove = debounce(count,1000);
实现效果如下:
2.立即执行版
触发事件后会立即执行,然后n秒内不触发事件才能继续执行函数的效果。用法同上。
// 立即执行版
function debounce(func, wait) {
let timer;
return function() {
let context = this; // 这边的 this 指向谁?
let args = arguments; // arguments中存着e
if (timer) clearTimeout(timer);
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait)
if (callNow) func.apply(context, args);
}
}
实现效果如下:
3.合成版
// 合成版
/**
* @desc 函数防抖
* @param func 目标函数
* @param wait 延迟执行毫秒数
* @param immediate true - 立即执行, false - 延迟执行
*/
function debounce(func, wait, immediate) {
let timer;
return function() {
let context = this,
args = arguments;
if (timer) clearTimeout(timer);
if (immediate) {
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait);
if (callNow) func.apply(context, args);
} else {
timer = setTimeout(() => {
func.apply(context, args);
}, wait)
}
}
}
三、节流
设置状态锁,短时间内高频率触发只有第一次触发成功。
1.时间戳版
可以看到,在持续触发事件的过程中,函数会立即执行,并且每 1s 执行一次。
// 非立即执行版
function throttle(func, wait) {
let previous = 0;
return function() {
let now = Date.now();
let context = this;
let args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}
}
我们是这样使用的:
content.onmousemove = throttle(count,1000);
实现效果如下:
2.定时器版
在持续触发事件的过程中,函数不会立即执行,并且每 1s 执行一次,在停止触发事件后,函数还会再执行一次。
// 立即执行版
// 定时器版
function throttle(func, wait) {
let timeout;
return function() {
let context = this;
let args = arguments;
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
实现效果如下:
我们应该可以很容易的发现,其实时间戳版和定时器版的节流函数的区别就是,时间戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内结束的时候。
3.合成版
/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 表时间戳版,2 表定时器版
*/
function throttle(func, wait, type) {
if (type === 1) {
let previous = 0;
} else if (type === 2) {
let timeout;
}
return function() {
let context = this;
let args = arguments;
if (type === 1) {
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
} else if (type === 2) {
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
}
总结
以上就是今天要讲的内容。