概念
函數(shù)防抖(debounce)
當(dāng)調(diào)用動作過n毫秒后,才會執(zhí)行該動作,若在這n毫秒內(nèi)又調(diào)用此動作則將重新計算執(zhí)行時間
函數(shù)節(jié)流(throttle)
預(yù)先設(shè)定一個執(zhí)行周期,當(dāng)調(diào)用動作的時刻大于等于執(zhí)行周期則執(zhí)行該動作,然后進(jìn)入下一個新周期
函數(shù)節(jié)流(throttle)與
函數(shù)防抖(debounce)都是為了限制函數(shù)的執(zhí)行頻次,以優(yōu)化函數(shù)觸發(fā)頻率過高導(dǎo)致的響應(yīng)速度跟不上觸發(fā)頻率,出現(xiàn)延遲,假死或卡頓的現(xiàn)象。
比如如下的情況:
- window對象的resize、scroll事件
- 拖拽時的mousemove事件
- 文字輸入、自動完成的keyup事件
可以拿我們平時坐電梯為例來形象地表述二者的區(qū)別
函數(shù)防抖:如果有人進(jìn)電梯(觸發(fā)事件),那電梯將在10秒鐘后出發(fā)(執(zhí)行事件監(jiān)聽器),這時如果又有人進(jìn)電梯了(在10秒內(nèi)再次觸發(fā)該事件),我們又得等10秒再出發(fā)(重新計時)。
函數(shù)節(jié)流
:保證如果電梯第一個人進(jìn)來后,10秒后準(zhǔn)時運送一次,這個時間從第一個人上電梯開始計時,不等待,如果沒有人,則不運行
實現(xiàn)
函數(shù)防抖(debounce)
function _debounce(fn,wait){
var timer = null;
return function(){
clearTimeout(timer)
timer = setTimeout(()=>{
fn()
},wait)
}
}
function _log(){
console.log(1)
}
window.onscroll = _debounce(_log,500)
但是,仔細(xì)想想,上面的實現(xiàn)方式還是有一定的缺點。如果頁面很長,我們一直在滾動頁面,那_log方法就一直不會被執(zhí)行。所以我們可以升級一下上述的防抖方法。
function _debounce(fn,wait,time){
var previous = null; //記錄上一次運行的時間
var timer = null;
return function(){
var now = +new Date();
if(!previous) previous = now;
//當(dāng)上一次執(zhí)行的時間與當(dāng)前的時間差大于設(shè)置的執(zhí)行間隔時長的話,就主動執(zhí)行一次
if(now - previous > time){
clearTimeout(timer);
fn();
previous = now;// 執(zhí)行函數(shù)后,馬上記錄當(dāng)前時間
}else{
clearTimeout(timer);
timer = setTimeout(function(){
fn();
},wait);
}
}
}
function _log(){
console.log(1)
}
window.onscroll = _debounce(_log,500,2000)
函數(shù)節(jié)流(throttle)
function _throttle(fn, time) {
let _self = fn,
timer,
firstTime = true //記錄是否是第一次執(zhí)行的flag
return function() {
let args = arguments, //解決閉包傳參問題
_me = this //解決上下文丟失問題
if(firstTime) { //若是第一次,則直接執(zhí)行
_self.apply(_me, args)
return firstTime = false
}
if(timer) { //定時器存在,說明有事件監(jiān)聽器在執(zhí)行,直接返回
return false
}
timer = setTimeout(function() {
clearTimeout(timer)
timer = null
_self.apply(_me, args)
}, time || 500)
}
}
function _log(){
console.log(1)
}
window.onscroll = _throttle(_log,500)
ES6中的函數(shù)防抖和函數(shù)節(jié)流
//函數(shù)節(jié)流
const throttle = (fun, delay) => {
let last = null;
return () => {
const now = + new Date();
if (now - last > delay) {
fun();
last = now;
}
}
}
//實例
const throttleExample = throttle(() => console.log(1), 1000);
//調(diào)用
throttleExample();
throttleExample();
throttleExample();
//函數(shù)防抖
const debouce = (fun, delay) => {
let timer = null;
return () => {
clearTimeout(timer);
timer = setTimeout(() => {
fun();
}, delay);
}
}
//實例
const debouceExample = debouce(() => console.log(1), 1000);
//調(diào)用
debouceExample();
debouceExample();
debouceExample();