在前端开发中,经常会遇到频繁触发某一事件的情况,如 scroll、mousemove、onchange等。这种高频率的触发会造成卡顿等现象。
解决这种问题通常有两种方法:防抖 和 节流
防抖 debounce
防抖原理:事件触发 n 秒后才执行,如果在一个事件触发的 n 秒内又触发了这个事件,以新的事件的时间为准,n 秒后才执行。总之,就是要触发完事件 n 秒内不再触发事件。
html
<input type="text" id="inp" />
基础版本:
function debounce(func, delay) {
var timer; //计时器id
return function () {
clearTimeout(timer) //清除计时器
timer = setTimeout(func, delay);
}
}
// 调用
inp.oninput = debounce(function(){console.log("test"),1000)
好了,一个基础的防抖函数就完成了。
但这样写有两个问题没有解决:this指向 和 event对象
this
//如果输出this, 指向window
inp.oninput = debounce(function(){console.log(this),1000)
event
function debounce(func, delay) {
var timer; //计时器id
return function () {
clearTimeout(timer) //清除计时器
timer= setTimeout(func, delay);
}
}
function bing(e) {
console.log(e)
}
// 调用
inp.oninput = debounce(bing, 1000)
//输出 undefined
完善后的代码
function debounce(func, delay) {
var timer; //计时器id
return function () {
let _this = this; //保留this
let _arg = arguments; //保留event
clearTimeout(timer) //清除计时器
timer = setTimeout(function(){
func.apply(_this,_arg) //改变指向
}, delay);
}
}
function bing(e) {
console.log(e,this.value)
}
// 调用
inp.oninput = debounce(bing, 1000)
节流 throttle
节流原理 :特定的时间内周期,事件只会执行一次,不管被触发了多少次。
如一些抽奖系统等。
节流的实现目前有两种主流方式:时间戳 和 定时器
HTML
<span id='show'>0</span>
<button id="ibox">click</button>
script
//节流
let show = document.querySelector('#show'),
ibox = document.querySelector('#ibox')
function throttle(fn, wait) {//shell函数
let lastTime = 0
return function (e) {
let nowTime = new Date().getTime()
if (nowTime - lastTime > wait) {
fn.apply(this, arguments)
lastTime = nowTime
}
}
}
function buy(e) {
show.innerText = parseInt(show.innerText) + 1
}
ibox.onclick = throttle(buy, 1000)