引言: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))
复制代码