防抖:
什么是防抖?
首先我们想象一下这个场景,如果在一个区域内设置鼠标移动事件,那一旦我们将鼠标移入这个区域内,这个事件就会被持续触发,导致每次改变都会重新渲染一次页面让性能损耗很大,这种情况下我们就需要用到防抖,那究竟什么是防抖呢?
触发高频事件后一段时间内函数只会执行一次,如果这段时间内高频事件再次被触发,则重新计算时间;
<div id="contain">
</div>
<button id="btn">点击取消防抖</button>
<script>
//创建一个防抖函数
function deBounce(fun, wait, immediate) {
var timer, result
let debounced = function () {
// 改变this的指向问题
let _this = this
let args = arguments
// console.log(args)
clearTimeout(timer)
if (immediate) {
// 立即执行的函数
let callNow = !timer
timer = setTimeout(() => {
timer = null
}, wait)
if (callNow) result = fun.apply(_this, args)
} else {
timer = setTimeout(() => {
result = fun.apply(_this, args)
}, wait)
}
return result
}
debounced.cancel = function () {
clearTimeout(timer)
timer = null
}
return debounced
}
let count = 0
let container = document.querySelector('#contain')
let btn = document.querySelector('#btn')
function changeCount() {
console.log(this)
container.innerHTML = count++
}
let chCount = deBounce(changeCount, 3000)
btn.onclick = function () {
console.log(chCount);
}
// 使用防抖处理
container.onmousemove = chCount
// 不使用防抖处理
// container.onmousemove = changeCount
</script>
</body>
上述代码中在3s内如果触发了onmousemove时间就会清除定时器重新开始计时。
防抖使用应用场景:
- scoll窗口滚动事件
- 搜索框输入查询
- 表单验证
- 按钮提交事件
- 浏览器窗口缩放——resize事件
节流:
什么是节流?
在一段时间内一直触发某个函数,每隔一段时间该函数只执行一次。
通常我们实现节流有两种方式:基于定时器和基于时间戳来实现
基于定时器:
// 创建节流函数
function throttle(fun, wait) {
//声明保存this,参数,计时器的变量
let _this, args, timer
return function () {
// 改变this指向
_this = this
args = arguments
if (!timer) {
timer = setTimeout(() => {
timer = null
fun.apply(_this, args)
}, wait)
}
}
}
该方法的不足在于——不顾头顾尾(第一次不执行,最后一次执行)。
基于时间戳实现:
function throttle(fun, wait) {
let _this, args
// 之前的时间戳
let previous = 0
return function () {
// 获取当前时间戳
_this = this
args = arguments
let now = new Date().valueOf()
if (now - previous > wait) {
fun.apply(_this, args)
//立即执行
previous = now
}
}
}
该方法的不足在于——顾头不顾尾(第一次调用立即执行,最后一次调用失效)。
既然上述两个方法一个不顾头,一个不顾尾,那我们就可以将两种方法混合在一起就产生了一个完美的解决方案——混合实现
// 混合实现————顾头顾尾
function throttle(fun, wait) {
let _this, args, timer
// 之前的时间戳
let previous = 0
let later = function () {
previous = new Date().valueOf()
timer = null
fun.apply(_this, args)
}
return function () {
// 获取当前时间戳
_this = this
args = arguments
let now = new Date().valueOf()
if (now - previous > wait) {
if (timer) {
clearTimeout(timer)
timer = null
}
fun.apply(_this, args)
//立即执行
previous = now
} else if (!timer) {
timer = setTimeout(later, wait)
}
}
}
节流的应用场景:
1.dom元素的拖拽实现
2.计算鼠标移动的距离
3.监听scroll滚动事件
4.后台请求数据时可以使用节流