函数函数防抖防抖是我们解决频繁触发DOM事件的两种常用解决方案。防抖和截流的应用场景有很多,输入框持续输入、将输入内容远程校验、多次触发点击事件、onScroll等等。
我们举个例子:我们在进行输入搜索的时候,我们会在一个输入框中输入我们想要的搜索的key,这个key会每次都像后端发送请求,获取搜索结果并显示。如果说我们输入速度特别快的话,就会有一种可能就是在很短时间内像后端发送很多的个请求,造成后端的接口的拥堵问题,另一方面每次搜索的结果的速度时不一样的,返回的速度也是有区别的,就是这些小小的区别会造成我们显示的结果并不是我们想要的等等问题。
解决类似于上面的问题就会用到防抖或者是节流。其实对于防抖和节流很多的库中都有实现,比如说lodash
还有就是有一个专门的防抖节流库throttle-debounce
函数防抖(debounce),就是指触发事件后,在 n 秒内函数只能执行一次,如果触发事件后在 n 秒内又触发了事件,则会重新计算函数延执行时间。
简单的实现
根据上面我们介绍的概念,我们先来简单的分析一下,防抖函数具备的那些特点,以及具体的实现思路:
防抖的具备的特点:
好了根据上面的特点,我们来实现一个简单的防抖函数:
function debounce(fn,wait){
var timer = null; // 这里我们需要有一个标
return function(){
if(timer !== null){
clearTimeout(timer);
}
timer = setTimeout(fn,wait);
}
}
// 下面是具体的使用方法
function handle(){
console.log(Math.random());
}
window.addEventListener("resize",debounce(handle,1000));
简单实现的缺陷以及如何改造
上面的简单的实现乍一看没什么问题,但是实际使用的时候我们会面临着以下几个问题:
this
,那么这this指的是什么)handle
中使用这个参数呢?)面对上面的问题,我们接下来对我们的防抖函数进行改造一下。
function debounce(func, wait, immediate) {
var timeout, result;
var later = function (context, args) {
timeout = null
result = func.apply(context, args);
};
var debounced = function () {
var context = this
var args = arguments
if (immediate) {
var callNow = !timeout;
if (callNow) {
later(context, args)
}
}
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(function () {
later(context, args)
}, wait)
return result
};
debounced.cancel = function () {
clearTimeout(timeout);
timeout = null;
};
return debounced;
}
函数防抖的使用场景
上面是一个防抖函数的一个实现,有了函数的防抖,但是函数防抖的使用场景有哪些?
函数的节流就是限制一个函数在一定时间内只能执行一次。
接下来我们根据概念具体分析函数节流具备的特点:
根据上面的这个点我们首先能能够想到的实现思路就是:
接下来具体实现一下:
function throttle(func, wait) {
var previous = 0;
return function() {
var now = +new Date();
var context = this;
if (now - previous >= wait) {
func.apply(context, arguments);
previous = now; // 执行后更新 previous 值
}
}
}
没错,这是能够做到函数的节流的,但是这又同样出现一个问题,就是最后一次的问题,也就是终点问题。我们举个例子,比如说我们设置的wait是分钟,但是在59秒的时候触发了一次,这个时候函数是不会被执行的。会丢失一些我们想要的最终态。
为了解决上面的问题,我们稍微的改变一下我们的实现思路:
用定时器实现时间间隔。
具体的实现如下:
function throttle(func, wait) {
var time
return function(){
var context = this
if(!time){
time = setTimeout(function(){
func.apply(context, arguments)
time = null
}, wait)
}
}
}
接下来将他们进行细节的优化一下:
throttle = function(func, wait, options) {
var timeout, context, args, result;
var previous = 0;
if (!options) options = {};
var later = function() {
previous = options.leading === false ? 0 : new Date();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
var throttled = function() {
var now = new Date();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
throttled.cancel = function() {
clearTimeout(timeout);
previous = 0;
timeout = context = args = null;
};
return throttled;
};
函数节流的具体使用场景
到此为止,相信各位应该对函数节流有了一个比较详细的了解,那函数节流一般用在什么情况之下呢?
目前遇到过的使用场景就是这些了,不过理解了原理,小伙伴可以把它运用在需要用到它的任何场合,提高执行效率。
以上就是我个人对函数的防抖和节流的一个理解。在项目中有用到的地方,为了效率平时是需要多注意的。
原文:https://www.cnblogs.com/ShuiNian/p/12985489.html