防抖 debounce
函数防抖就是在函数需要频繁触发的情况下,只有足够的空闲时间,才执行一次。
防抖的原理:你尽管触发事件,但是我一定在事件触发的n秒后才执行,如果你在触发事件n秒内又触发了这个事件,那我就以新事件的时间为准,n秒后在执行
典型应用
- 百度搜索框在输入稍有停顿时才更新推荐热词。
// 频繁触发时,清楚对应的定时器,然后再开一个定时器,delay秒后执行
function debounce(handler, delay) {
delay = delay || 300;
var timer = null;
return function () {
// 保留调用时的this上下文
var _self = this,
// 保留调用时传入的参数
_args = arguments;
// 每次事件触发时 都去清除之前的旧定时器
if(timer){
clearTimeout(timer);
}
// 设定新定时器
timer = setTimeout(function () {
handler.apply(_self, _args);
}, delay);
}
}
实例
// 不希望被频繁调用的函数
function add(counterName) {
console.log(counterName + ": " + this.index++);
}
// 需要的上下文对象
let counter = {
index: 0
}
// 防抖的自增函数,绑定上下文对象counter
let db_add = debounce(add, 10).bind(counter)
// 每隔500ms频繁调用3次自增函数,但因为防抖的存在,这3次内只调用一次
// setInterval(function () {
// db_add("someCounter1");
// db_add("someCounter2");
// db_add("someCounter3");
// }, 500)
/**
* 预期效果:
*
* 每隔500ms,输出一个自增的数
* 即打印:
someCounter3: 0
someCounter3: 1
someCounter3: 2
someCounter3: 3
*/
节流 throttle
一个函数只有在大于执行周期时才执行,周期内调用不执行。好像水滴积攒到一定程度才会触发一次下落一样。
典型应用:
节流原理:如果你持续触发事件,每隔一段时间,只会执行一次事件
- 鼠标移动事件
- 窗口调整
- 页面滚动
function throttle(handler, wait) {
wait = wait || 300;
var lastTime = 0; // 上一次触发回调的时间
return function () {
// 保留调用时的this上下文
var _self = this,
// 保留调用时传入的参数
_args = arguments;
// 记录本次触发回调的时间
var nowTime = new Date().getTime();
if ((nowTime - lastTime) > wait) {
// 如果时间间隔大于设定的时间间隔阈值 则执行回调
handler.apply(_self, _args);
lastTime = nowTime;
}
}
}
使用节流后 在盒子内移动 每300毫秒打印一次结果
let handleMouseMove = throttle(function(e){
console.log(e.pageX,e.pageY);
})
// 使用节流后 在盒子内移动 每300毫秒打印一次结果
document.querySelector(".box").addEventListener("mousemove",handleMouseMove)
复杂但好用版:
function throttle(fn, interval, context, firstTime) {
let timer;
firstTime = typeof firstTime !== 'undefined' ? firstTime : true;
return function() {
let args = arguments;
let __me = this;
if (typeof context !== 'undefined') {
__me = context;
}
if (firstTime) {
fn.apply(__me, args);
return (firstTime = false);
}
if (timer) {
return false;
}
timer = setTimeout(function() {
clearTimeout(timer);
timer = null;
fn.apply(__me, args);
}, interval);
};
}
节流与防抖的本质
以闭包的形式存在,通过对事件对应的回调函数进行包裹、以自由变量的形式缓存时间信息,最后用定时器或时间差来控制事件的触发频率。