前言
如果经常在一些技术社区"散步"的话,函数的"防抖"和"节流"这两个词被提到的频率还是挺高的,但是做了一年的开发,却没有在自己写的项目中用到,还是要好好反思一下。痛定思痛,好好学习。
防抖(debounce)
原理🍖
事件执行n秒后再执行回调,如果在这n秒内再次被触发,则n秒重新计算。
应用场景🍔
- 搜索框: 用户输入完关键词再去触发搜索行为;
- window的resize事件:用户调整大小结束之后再去触发相应的操作;
效果预览
- 防抖前
// 代码预览
<input id="debounce"></input> 搜索框
function search(e) {
console.log('开始搜索' , e.target.value)
}
const de = document.getElementById('debounce')
de.addEventListener('input', search)
- 防抖后
// 代码预览
<input id="debounce"></input> 搜索框
function search(e) {
console.log('开始搜索' , e.target.value)
}
function debounce(fn, delay) {
let ts = null
console.log('debounce')
return function() {
clearTimeout(ts)
ts = setTimeout(() => {
fn.apply(this, arguments)
}, delay)
}
}
const de = document.getElementById('debounce')
de.addEventListener('input', debounce(search, 1000))
是真的理解了吗?(思考)👺
- 为什么debounce这个字符串只是打印了一次?
addEventListener绑定的时候,用的是debounce这个函数的返回值,其实对比一下防抖前就很容易理解了。
- 为什么fn.apply(this, arguments),而不能是fn()?
其实在当前这个程序中,我们可以用fn(…argruments)来替换fn.apply(this, arguments),因为我们在search中也没有用到this。当然也可以用call,fn.call(this, …arguments)
- setTimeout中的函数为什么用箭头函数?
箭头函数没有this,如果不用箭头函数,this可就指向了setTimeout,就的换个写法
function debounce(fn, delay) {
let ts = null
console.log('debounce')
return function() {
clearTimeout(ts)
const context = this, args = arguments
ts = setTimeout(function() {
fn.apply(context, args)
}, delay)
}
}
节流(throttle)
原理🍖
事件执行n秒后再执行回调,如果再这n秒内再次被触发,则忽略。通俗点讲,就想王者荣誉中的英雄技能的冷却时间,没到冷却的时间,你怎么点都是没有效果的。
应用场景
- 表单提交: 多次点击提交按钮
- 滚动条scroll事件:当滚动条滑动到底部的时候再去请求其他数据
效果预览(节流前的效果在前面以及体现,我们直接看节流后的效果)
// 代码预览🍔
function throttle(fn, delay) {
let ts = null
return function() {
if (!ts) {
ts = setTimeout(() => {
fn.call(this, ...arguments)
ts = null
}, delay)
}
}
}
问题考虑👺
- 往往我们希望的是,点击按钮需要立即执行,第一次之后再做节流,让我们对代码做一些优化
function throttle(fn, delay) {
let ts = null
let first = true
return function() {
if (first) {
fn.call(this, ...arguments)
first = false
}
if (!ts) {
ts = setTimeout(() => {
fn.call(this, ...arguments)
ts = null
}, delay)
}
}
}
- 现在来看一下效果
总结与思考
- 防抖和节流看似简单的两个个函数,却涵盖了很多的基础知识点,我们不妨思考一下:闭包、函数作用域、this指向等问题
- 思考在我们的项目中为什么没有用到,之后是否作为优化添加上这两个效果。