引言:bash
在咱們的開發過程當中都會遇到高頻事件,好比說onscroll事件,每當頁面滾動的時候,每一秒可能會觸發幾十次的函數執行, 假如onscroll還綁定了回調函數,並對dom進行重排,那麼每一秒執行幾十次dom渲染,若是dom操做過多,那麼頁面可能會出現卡頓的現象。app
或者resize行爲每一次頁面窗口的變化都會綁定dom的渲染也會出現上述狀況。爲了優化高頻事件(oninput,onkeyup,onkeydown),下降代碼執行頻率,採用優化方案函數的迴流和防抖。dom
函數在必定時間內執行一次核心代碼。好比人在一段時間眨一次眼睛。函數
let btn = document.getElementById('btn')
function logger() {
console.log('logger') // 每一秒打印一次
}
function throttle(func, wait) {
let previous = 0
return function() {
let now = Date.now()
if (now - previous > wait) {
func.apply(this, arguments)
previous = now
}
}
}
btn.addEventListener('click', throttle(logger, 1000))
複製代碼
logger
函數用來測試,正常每次點擊都會打印'logger', 節流處理每一秒打印一次'logger'測試
previous
相對於上一次點擊的時間 now
每次點擊記錄的事件優化
now - previous > wait
第一次由於previous
爲 0 第一次執行 logger
函數, 把previous
賦值爲當前時間ui
第二次的時候只有當前時間和上次時間大於 wait
(1000毫秒)的時候纔會再次執行logger
this
用戶最後一次的點擊事件觸發無論是否小於wait
這裏是1s咱們須要記錄下來,觸發一次logger
spa
function throttle(func, wait, options) {
let previous = 0
let timer;
let me = this;
let later = function() {
previous = Date.now()
func.apply(me, arguments)
}
let throttled = function() {
let now = Date.now();
let remaining = wait - (now - previous);
if (remaining <= 0) { // 小於0 說明點擊事件間隔大於1000ms
if (timer) {
clearTimeout(timer)
timer = null
}
func.apply(me, arguments)
previous = now
} else if (!timer && options.trailing) {
timer = setTimeout(later, remaining)
}
}
return throttled
}
btn.addEventListener('click', throttle(logger, 1000, { trailing: true}))
複製代碼
trailing
等於 true
開啓模式code
點擊事件時間間隔越短並小於1s ,now-previous
值越小, 那麼 wait - (now - previous)
值必定大於0 remaining > 0
第一次click !timer && options.trailing
成立, 結束後多執行一次later
下一次 先清除timer
再進入判斷 執行下一次later
函數在執行完畢的時候,才觸發核心代碼執行, 好比在作電梯的時候,若是關門的過程當中,有人要上來,不會走,等他上來一塊走。
function logger() {
console.log('logger')
}
function debounce(func, wait) {
let timeout;
return function() {
clearTimeout(timeout)
timeout = setTimeout(() => {
func.apply(this, arguments)
timeout = null
}, wait)
}
}
btn.addEventListener('click', debounce(logger, 1000))
複製代碼
每次高頻率click的時候都會清除上一次的定時器不會執行代碼, 只有等到鬆開1s後纔會執行代碼
每次第一次點擊的時候先執行一次
function logger() {
console.log('logger')
}
function debounce(func, wait, immediate) {
let timeout;
return function() {
clearTimeout(timeout)
if(immediate) {
let callNow = !timeout
if(callNow) func.apply(this, arguments)
}
timeout = setTimeout(() => {
func.apply(this, arguments)
timeout = null
}, wait)
}
}
btn.addEventListener('click', debounce(logger, 1000, true))
複製代碼