一、js防抖
特点:
- 当事件触发时,相应的函数并不会立即触发,而是会等待一定的时间(非常短的时间);
- 当事件密集触发时,函数的触发会被频繁的推迟;
- 只有等待了一段时间也没有事件触发,才会真正的执行响应函数;
应用场景:
- Ø输入框中频繁的输入内容,搜索或者提交信息;
- Ø频繁的点击按钮,触发某个事件;
- Ø监听浏览器滚动事件,完成某些特定操作;
- Ø用户缩放浏览器的resize事件;
实现方式
第三方库实现
<input type="text"> <!--html标签-->
<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.1/underscore-umd-min.js"></script>
<script>
const inputEl = document.querySelector("input")
let counter = 0
const inputChange = function(event) {
console.log(`发送了第${++counter}次网络请求`, this, event)
}
// 防抖处理
inputEl.oninput = _.debounce(inputChange, 2000)//当用户停止输入的时候延时2秒后执行
</script>
手动实现(原理)
- 基本实现:
function debounce(fn, delay) {
// 1.定义一个定时器, 保存上一次的定时器
let timer = null
// 2.真正执行的函数
const _debounce = function() {
// 取消上一次的定时器
if (timer) clearTimeout(timer)
// 延迟执行
timer = setTimeout(() => {
// 外部传入的真正要执行的函数
fn()
}, delay)
}
return _debounce
}
- this绑定/事件对象
function debounce(fn, delay) {
// 1.定义一个定时器, 保存上一次的定时器
let timer = null
// 2.真正执行的函数
const _debounce = function(...args) {
// 取消上一次的定时器
if (timer) clearTimeout(timer)
// 延迟执行
timer = setTimeout(() => {
// 外部传入的真正要执行的函数
fn.apply(this, args)
}, delay)
}
return _debounce
}
- 第一次立即执行
function debounce(fn, delay, immediate = false) {
// 1.定义一个定时器, 保存上一次的定时器
let timer = null
let isInvoke = false
// 2.真正执行的函数
const _debounce = function(...args) {
// 取消上一次的定时器
if (timer) clearTimeout(timer)
// 判断是否需要立即执行
if (immediate && !isInvoke) {
fn.apply(this, args)
isInvoke = true
} else {
// 延迟执行
timer = setTimeout(() => {
// 外部传入的真正要执行的函数
fn.apply(this, args)
isInvoke = false
}, delay)
}
}
return _debounce
}
- 取消功能
function debounce(fn, delay, immediate = false) {
// 1.定义一个定时器, 保存上一次的定时器
let timer = null
let isInvoke = false
// 2.真正执行的函数
const _debounce = function(...args) {
// 取消上一次的定时器
if (timer) clearTimeout(timer) // 判断是否需要立即执行 if (immediate && !isInvoke) {
fn.apply(this, args)
isInvoke = true
} else {
// 延迟执行
timer = setTimeout(() => {
// 外部传入的真正要执行的函数
fn.apply(this, args)
isInvoke = false
timer = null
}, delay)
}
}
// 封装取消功能
_debounce.cancel = function() {
if (timer) clearTimeout(timer)
timer = null
isInvoke = false
}
return _debounce
}
- 函数返回值
<body>
<input type="text">
<script src="./05_debounce-v5-函数返回值.js"></script>
<script>
const inputEl = document.querySelector("input")
let counter = 0
const inputChange = function(event) {
console.log(`发送了第${++counter}次网络请求`, this, event)
// 返回值
return "aaaaaaaaaaaa"
}
// 防抖处理--拿到包装好的事件处理回调函数--回调函数的返回值是Promise
const debounceChange = debounce(inputChange, 3000, false, (res) => {
console.log("拿到真正执行函数的返回值:", res)
})
const tempCallback = () => {
debounceChange().then(res => {
console.log("Promise的返回值结果:", res)
})
}
inputEl.oninput = tempCallback
</script>
</body>
</html>
二、js节流
特点:
- 当事件触发时,会执行这个事件的响应函数;
- 如果这个事件会被频繁触发,那么节流函数会按照一定的频率来执行函数;
- 不管在这个中间有多少次触发这个事件,执行函数的频繁总是固定的;
应用场景:
- Ø 游戏中的一些设计–王者荣耀 英雄的普攻;
- Ø监听页面的滚动事件;
- Ø 鼠标移动事件;
- Ø 用户频繁点击按钮操作;
实现方式:
第三方库实现
<input type="text"> <!--html标签-->
<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.1/underscore-umd-min.js"></script>
<script>
const inputEl = document.querySelector("input")
let counter = 0
const inputChange = function(event) {
console.log(`发送了第${++counter}次网络请求`, this, event)
}
// 节流处理
inputEl.oninput =_.throttle(inputChange, 2000)//当用户不断触发事件按照2秒的频率执行
</script>
手动实现(原理)
- 基本实现:
function throttle(fn, interval, options) {
// 1.记录上一次的开始时间
let lastTime = 0
// 2.事件触发时, 真正执行的函数
const _throttle = function() {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime()
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
// 2.3.真正触发函数
fn()
// 2.4.保留上次触发的时间
lastTime = nowTime
}
}
return _throttle
}