在前端开发的过程中,我们经常会需要绑定一些持续触发的事件,如 resize、scroll、mousemove 等等,但有些时候我们并不希望在事件持续触发的过程中那么频繁地去执行函数。
一般来说,我们会用防抖或者节流方式去解决他们
<!--index.html文件 -->
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="IE=edge, chrome=1">
<title>debounce</title>
<style>
#container{
width: 100%; height: 200px; line-height: 200px; text-align: center; color: #fff; background-color: #444; font-size: 30px;
}
</style>
</head>
<body>
<div id="container"></div>
//script文件
<script>
var count = 1;
var container = document.getElementById('container');
function getUserAction() {
container.innerHTML = count++;
};
container.onmousemove = getUserAction;
</script>
不加防抖或者节流
可以看出,在短时间内,调用一个函数多次
防抖(debounce)
触发事件在n秒内只执行一次,如果在这n秒内再次被触发,则再次计算执行时间(n秒)
var count = 1;
var container = document.getElementById('container');
function getUserAction() {
container.innerHTML = count++;
};
function debounce(func, wait) {
let timeout;
return function () {
let context = this; //让func函数中this指向,指向原来的this
let args = arguments;
if(timeout)clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context,args);
}, wait);
}
}
container.onmousemove = debounce(getUserAction,1000);
效果如下
可以看出,函数只有当我们停止触发之后一秒才会执行(使用了延时器)
同时,在函数中使用了context来保存this,因为在延时器中this指向window,所以为了保证与原来func函数中的this指向相同,则使用了context保存this,并用apply传入this。
节流(throttle)
是指连续出发事件,但是在n秒钟内只执行一次函数节流会稀释函数的执行频率
var count = 1;
var container = document.getElementById('container');
function getUserAction() {
container.innerHTML = count++;
};
function debounce(func, wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if(!timeout){
timeout = setTimeout(() => {
timeout = null;
func.apply(context,args);
}, wait);
}
}
}
container.onmousemove = debounce(getUserAction,1000);
可以看出,节流与防抖函数非常相似
效果如下
可以看到,在持续触发事件的过程中,函数不会立即执行,并且每 1s 执行一次,在停止触发事件后,函数还会再执行一次。