函数防抖(debounce): 事件响应函数在一段时间后才执行。如果在这段时间内再次调用,则重新计算执行时间,当预定时间内没有再次执行,该函数则执行相应时间
应用场景:
函数节流(throttle): 如果持续触发事件,每隔一段事件只执行一次事件
应用场景
解决:
1.使用underscore.js库
https://underscorejs.net/#
2.手写(仿underscore.js)
防抖实例
let container = document.querySelector("#container")
container.onmousemove = debounce(dosomething, 1000)
function dosomething(e) {
container.innerHTML = count++
// this指向container
console.log(this)
//如果有返回值
return '想要的结果'
}
// immediate 立即调用,不等延迟
function debounce(func, wait, immediate) {
let timer, arg, context
let result //返回值
let decounced = function () {
context = this
args = arguments
if (timer) clearTimeout(timer)
if (immediate) {
// 立即执行
let callNow = !timer
timer = setTimeout(() => {
timer = null
}, wait)
// 返回值
// this指向container
if (callNow) result = func.apply(this, arg)
} else {
// 不会立即执行
timer = setTimeout(() => {
func.apply(this, arg)
}, wait)
}
// 返回值
return result
}
// 取消防抖方法
decounced.cancel = function () {
clearTimeout(timer)
timer = null //避免内存泄漏
}
return decounced
}
// 取消防抖
let doSome = debounce(dosomething, 1000)
// 取消
btn.onclick = function () {
doSome.cancel()
}
节流实例
1.使用定时器
function throttle(func, wait) {
let args, timeout
let context
return function () {
context = this
args = arguments
if (!timeout) {
timeout = setTimeout(() => {
timeout = null
// 改变this
func.apply(context, args)
}, wait)
}
}
}
function dosomething(e) {
container.innerHTML = count++
}
// 调用
container.onmousemove = throttle(dosomething, 1000)
2.时间戳
function throttle (func, wait) {
let args
// 之前的时间戳
let previos = 0;
return function () {
args = arguments
// 获取当前时间戳
let now = new Date().valueOf()
// 当前时间-之前时间大于等待时间,执行
if (now - previos > wait) {
// 立即执行
func.apply(this, args)
// 之前时间重新赋值
previos = now
}
}
}
function dosomething(e) {
container.innerHTML = count++
}
// 调用
container.onmousemove = throttle(dosomething, 1000)
3.使用时间戳和定时器优化(手写underscore)
// 时间戳方法 第一次触发,最后一次不触发
// 定时器方法 第一次不触发, 最后触发
// 第一次触发, 最后触发
function throttle1(func, wait) {
let args, timeout
let previos = 0
let later = function () {
previos = new Date().valueOf()
timeout = null
func.apply(this, args)
}
return function () {
args = arguments
let now = new Date().valueOf()
if (now - previos > wait) {
if (timeout) {
clearTimeout(timeout)
timeout = null
}
// 立即执行
func.apply(this, args)
previos = now
}
else if (!timeout) {
timeout = setTimeout(later, wait)
}
}
}
// 实现定时器和时间戳优化
// 第三个参数option:{leading: 第一次, trailing: 最后一次}
// {leading: true 第一次触发, trailing: true 最后一次也触发}
// {leading: true 第一次触发, trailing: false 最后一次不触发}
// {leading: false 第一次不触发, trailing: true 最后一次被触发}
// 同时为false 有bug, 同underscore.js
function throttle(func, wait, option) {
let args, timeout,context
let previos = 0
if(!option) option = {}
let later = function () {
previos = new Date().valueOf()
timeout = null
func.apply(context, args)
}
return function () {
args = arguments
context = this
let now = new Date().valueOf()
if(option.leading === false && !previos) {
previos = now
}
if (now - previos > wait) {
// 第一次回直接执行
if (timeout) {
clearTimeout(timeout)
timeout = null
}
// 立即执行
func.apply(context, args)
previos = now
}
else if (!timeout && option.trailing !== false) {
// 最后也会执行
timeout = setTimeout(later, wait)
}
}
}
function dosomething(e) {
container.innerHTML = count++
// 改变this指向
console.log(this)
return '结果'
}
// let doSome = throttle(dosomething, 10000, {
// leading: false, //禁止第一次执行
// trailing: false //禁止最后异常执行 不能同时为false,第二下进入是第一次不执行
// })
container.onmousemove = throttle2(dosomething, 2000, {
leading: false,
trailing: false
})