每日一句
Keep your friends close, but your enemies closer.
释义:亲近你的朋友,但更要亲近你的敌人。
背景
背景1:在前端开发中,增删改查接口是必会遇到,当在新增某个产品时,输入完标题等一系列字段时,点击保存手抖了或是网卡手见点了多次,这个时候你会发现怎么新增了好几条。
背景2:就一个input框搜索,做法是当input值发生变化时调接口去查询,只要改变了就会去查,你从接口请求中会看到请求了多次,太影响性能了。
从以上两个比较常见的背景可以看出,这不是我们想要的。为了限制在短时间内高频触发函数调用情况发生,防抖和节流应运而生了。
当然这只是其中的一种思路,你也可以换其他方式去解决,比如你可以点击保存或搜索时按钮不可点,等到接口请求回来再让按钮可点,中间的等待加上loading效果等。
防抖和节流是两种解决的策略,防抖和节流有时候会让我们迷惑,那什么是防抖,什么是节流,这两个到底有啥区别,具体怎么用等等,下面我们一起来看下。
防抖与节流
防抖debounce
顾名思议:防止抖动。一段时间内,事件在我们规定的间隔 n 秒内多次执行,回调只会执行一次。
代码实现:
- 非立即执行版本
<button id="save">保存</button>
<script>
function debounce(callback, wait) {
let timer;
return () => {
if (timer) clearTimeout(timer)
let ctx = this;
timer = setTimeout(() => {
callback.call(ctx, arguments)
}, wait)
}
}
function saveContent() {
console.log('save')
}
save.onclick = debounce(saveContent, 1000)
- 立即执行版本
<button id="save">保存</button>
<script>
function debounce(callback, wait) {
let timer;
return () => {
if (timer) clearTimeout(timer)
let ctx = this;
const callNow = !timer
timer = setTimeout(() => {
timer = null
}, wait)
if (callNow) callback.apply(ctx, [...arguments])
}
}
function saveContent() {
console.log('save')
}
save.onclick = debounce(saveContent, 1000)
- 优雅的封装
function debounce(callback, wait, immediate = false) {
let timer;
return () => {
if (timer) clearTimeout(timer)
if (immediate) {
let callNow = !timer;
timer = setTimeout(() => {
timer = null
}, wait)
if (callNow) callback.apply(this, [...arguments])
} else {
timer = setTimeout(() => {
callback.call(this, arguments)
}, wait)
}
}
}
节流throttle
顾名思议,控制流量。指连续触发事件但是在 n 秒中只执行一次函数。
代码实现:
- 定时器版本
function throttle(callback, wait){
let timer;
return () => {
if (!timer) {
timer = setTimeout(() => {
timer = null;
callback.apply(this, arguments)
}, wait)
}
}
}
function saveContent() {
console.log('save')
}
save.onclick = throttle(saveContent, 1000)
- 时间戳版本
function throttle(callback, wait){
let pre = 0;
return () => {
let now = Date.now();
if (now - pre >= wait) {
callback.apply(this, arguments)
pre = Date.now()
}
}
}
function saveContent() {
console.log('save')
}
save.onclick = throttle(saveContent, 1000)
- 优雅的封装
// type 0: 定时器版 1: 时间戳版
function throttle(callback, wait, type = 0){
if (type === 0) {
var timer;
} else if (type === 1) {
var pre = 0;
}
return () => {
if (type === 0) {
if (!timer) {
timer = setTimeout(() => {
timer = null;
callback.apply(this, arguments)
}, wait)
}
} else if (type === 1) {
let now = Date.now();
if (now - pre >= wait) {
callback.apply(this, arguments)
pre = Date.now()
}
}
}
}
function saveContent() {
console.log('save')
}
save.onclick = throttle(saveContent, 1000, 0)
防抖和节流的区别
防抖:对于连续的事件响应我们只需要执行一次回调
节流:一个函数执行一次后,只有大于设定的执行周期后才会执行第二次
应用场景
防抖:
- resize/onscroll事件
- button新增ajax请求一次就好
节流:
- DOM拖拽mousemove, 计算机鼠标移动距离mousemove
- mousedown/keydown 事件(单位时间只能做一件事)
- 监听滚动事件,如上拉加载,无限滚动等