防抖动不是什么新鲜事,相信很多切图仔都写过。
function debounce(fn, delay = 300) {
let timer;
return function() {
if (timer) {
clearTimeout(timer);
timer = setTimeout(() => {
fn();
}, delay);
}
}
}
// 比如我有一个button, 点击会触发btn_click()
btn_click() {
function doClick() {
// 我想执行的代码
}
debounce(doClick, 300)();
}
原理很简单,当user 300ms 以内第二次点击button的时候,会先把前一次的点击事件干掉,缓存第二次,重新计时300ms,如果第二个300ms 以内有再次点击,也会把前一次点击干掉,一直到超出300ms 为止,才执行doClick。
最近做了一个相当可怕的requirement,
- 允许user 输入input1
- user 点击btn1,set value to input1
- user 点击btn2,set value to input1
- user 点击btn3,如果input1原本非空,do nothing; 如果input1为空,set default value to input1
- user 点击btn4,如果user从来没有input 过input1,set input1 为空, 否则, keep input1 value。 hide input1, show input2
- 有一段nextTick 不断auto set value to input1
- btn1, btn2, btn3, btn4, input1.blur, auto refresh 除了set value to input1,还有一堆async functions 如果user 依次触发以上2345,你想象中的执行顺序是: btn1_click(), btn1_async1(), btn1_async2(), btn2_click(), btn2_async1(), ... 但实际上是, 执行btn1_click(), btn1_async1 入异步队列, btn1_async2 入异步队列, 执行btn2_click(), btn2_async1 入异步队列, ... , 执行btn1_async1(), 执行btn1_async2(), 执行btn2_async1(), ... 可想而知,如果user 无序快速click 这4个button,叠加auto refresh,最后input1里面是个什么鬼value,那只有鬼才知道了。 为了可控,我们试着引入debounce,并且让这4个button的click, input.blur,auto refresh 共享timer。我给它起了个名字叫shared debounce
function sharedDebounce(fn, delay = 300) {
return function() {
const that = this;
if (that.timer) {
clearTimeout(that.timer);
}
that.timer = setTimeout(() => {
fn();
clearTimeout(that.timer);
}, delay);
}
}
// 前端用vue写的
data() {
return {
timer: null
};
}
methods: {
btn1_click() {
function proceed() {
this.input1Value = '111';
this.btn1_async1();
this.btn1_async2();
}
sharedDebounce(proceed.bind(this), 300).apply(this);
}
btn2_click() {
function proceed() {
this.input1Value = '222';
this.btn2_async1();
}
sharedDebounce(proceed.bind(this), 300).apply(this);
}
}
如此,给所有button 和auto refresh 都加上shareDebounce。当user 无序快速click 这4个button,程序只会响应最后一个事件。
(原创文章,转载请注明出处)