函数节流
概念:
单位时间内触发多次事件,只执行一次其事件对应的回调函数
理解:
在单位事件内,不论触发多少次事件,只执行第一次事件对应的回调函数,并且在计时结束后响应(只认第一次事件的回调)
实现:
//延迟执行版本:
function throttle(fn,delay){
var timer = null
return function(){
if(timer){
return
}
timer = setTimeout(()=>{
fn.apply(this,arguments)
timer = null
},delay)
}
}
//立即执行版本:
function throttle(fn,delay=500){
let startTime = Date.now()
return function(){
let endTime = Date.now()
let diffValue = endTime - startTime
if(diffValue >= delay){
fn.call(this,arguments)
startTime = Date.now()
}
}
}
/*
方法1: 定时器方式实现
缺点:第一次触发事件不会立即执行fn,需要等delay间隔过后才会执行
*/
let throttle = (fn, delay) => {
let flag = false
return function(...args) {
if (flag) return
flag = true
setTimeout(() => {
fn(...args)
flag = false
}, delay)
}
}
/*
方法2:时间戳方式实现
缺点:最后一次触发回调与前一次的触发回调的时间差小于delay,则最后一次触发事件不会执行回调
*/
let throttle = (fn, delay) => {
let _start = Date.now()
return function(...args) {
let _now = Date.now(),
that = this
if (_now - _start > delay) {
fn.apply(that, args)
start = Date.now()
}
}
}
// 方法3:时间戳与定时器结合
let throttle = (fn, delay) => {
let _start = Date.now()
return function(...args) {
let _now = Date.now(),
that = this,
remainTime = delay - (_now - _start)
if (remainTime <= 0) {
fn.apply(that, args)
} else {
setTimeout(() => {
fn.apply(that, args)
}, remainTime)
}
}
}
/*
方法4:requestAnimationFrame实现
优点:由系统决定回调函数的执行机制,60Hz的刷新频率,每次刷新都会执行一次回调函数,不
会引起丢帧和卡顿
缺点:1.有兼容性问题2.时间间隔有系统决定
*/
let throttle = (fn, delay) => {
let flag
return function(...args) {
if (!flag) {
requestAnimationFrame(function() {
fn.apply(that, args)
flag = false
})
}
flag = true
}
}
运用:
函数防抖
概念:
事件触发后,在规定的时间后(单位时间)执行其事件对应的回调函数;如果在单位事件内再次触发事件,则重新计时
理解:
利用闭包将 timer 挂载到 window 上,每次触发事件就把上一次 timer 清除掉,直到最后一次事件执行回调函数(只认最后次)
运用:
作用:
优化高频率执行回调(例如:resize、keypress、scroll、mousemove等事件的回调)