函数防抖
概念: 函数防抖(debounce)是指在一定时间内,在动作被连续频繁触发的情况下,动作只会被执行一次,也就是说当调用动作过n毫秒后,才会执行该动作
ES5写法:
// debounce函数用来包裹我们的事件处理方法
function debounce(fn, delay){
// 持久化一个定时器
let timer = null
// 闭包函数可以访问timer
return function(){
// 通过 this 和 arguments 获得函数的作用域和参数
let context = this
let args = arguments
// 如果事件被触发,清除timer并重新开始计时
clearTimeout(timer)
timer = setTimeout(function() {
fn.apply(context, args)
}, delay)
}
}
function foo(){
console.log('You are scrolling!')
}
document.addEventListener('scroll', debounce(foo, 50));
复制代码
ES6写法:
export function debounce(fn, interval = 300) {
let timer = null;
return function () {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, interval);
};
}
let debounce = (fn, time = 50) => { // 防抖动 控制空闲时间
let timer;
return function (...args) {
let that = this;
clearTimeout(timer);
timer = setTimeout(fn.bind(that, ...args), time);
}
}
复制代码
原理:通过闭包保存一个标记来保存 setTimeout 返回的值,每当用户输入的时候把前一个 setTimeout clear 掉,然后又创建一个新的 setTimeout,这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数了。
函数节流
概念: 函数节流,就是让一个函数无法在很短的时间间隔内连续调用,只有当上一次函数执行后过了你规定的时间间隔,才能进行下一次该函数的调用。比如,在让缩放内容的操作在你不断改变窗口大小的时候不会执行,只有你停下来一会儿,才会开始执行。
原理:当我触发一个事件时,先setTimout让这个事件延迟一会再执行,如果在这个时间间隔内又触发了事件,那我们就clear掉原来的定时器,再setTimeout一个新的定时器延迟一会执行,就这样。
案例:这些概念的一个主要用例是某些DOM事件,如滚动和调整大小。例如,如果我们将一个滚动处理程序附加到元素,并将该元素向下滚动到5000px,则可能会看到超过100个事件触发。如果我们的事件处理程序执行一些工作(如重计算和其他DOM操作),我们可能会看到性能问题。如果你可以使执行该处理程序的次数减少,而没有太多的中断,那这些工作是值得的。
一些小例子:
1)等到用户停止调整窗口大小
2)在用户停止打字之前,不要触发ajax事件
4)计算页面的滚动位置,每50ms最多执行一次
5)在应用程序中拖动元素时,请确保良好的性能
ES5:
function throttle(fn, threshold){
var timeout
var start = new Date;
var threshhold = threshhold || 160
return function () {
var context = this,
args = arguments,
curr = new Date() - 0;
clearTimeout(timeout)//总是干掉事件回调
if(curr - start >= threshhold){
console.log("now", curr, curr - start)
//注意这里相减的结果,都差不多是160左右
fn.apply(context, args)
//只执行一部分方法,这些方法是在某个时间段内执行一次
start = curr
//重新开始计算时间
}else{
//让方法在脱离事件后也能执行一次
timeout = setTimeout(function(){
fn.apply(context, args)
}, threshhold);
}
}
}
var mousemove = throttle(function(e) {
console.log(e.pageX, e.pageY)
});
document.querySelector("#panel").addEventListener('mousemove', mousemove); 复制代码
ES6
export function throttle(fn, waitTime = 1000){
let lastTime = null
return function () {
let startTime = + new Date()
if (startTime - lastTime > waitTime || !lastTime) {
fn()
lastTime = startTime
}
}
}
let throttle = (fn, delay = 50) => {
//节流 控制执行间隔时间 防止频繁触发 scroll resize mousemove
let stattime = 0;
return function (...args) {
let curTime = new Date();
if (curTime - stattime >= delay) {
fn.apply(this, args);
stattime = curTime;
}
}复制代码
注意:函数节流(throttle)与 函数防抖(debounce)都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。
比如如下的情况:
window对象的resize、scroll事件
拖拽时的mousemove事件
文字输入、自动完成的keyup事件
总结:函数防抖实现的核心在于每次都去clear一个延时器,然后每次执行函数的时候,都去clear以前的延时器。只有当你中断事件的时候,才会去执行相应回调。而函数节流的核心是去判断当前时间和开始时间的间隔是否到达了设置的delay值,如果达到了,就执行一次回调。没有则不执行。
作者:李赫feixuan
链接:https://juejin.im/post/5b3e2cc8f265da0fab3ff8e2
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。