防抖函数
徐徐 抱歉选手

为什么需要防抖函数

在浏览器中,触发频繁的事件,如window的onresize、鼠标的mousemove、滚轮的wheel、文本输入框的验证等,因为这些事件被频繁触发,有可能导致大量的计算或者服务器资源消耗极大的操作,event handler就没有必要每一次触发都执行。

因此就有了函数防抖的概念,让事件触发的n秒内只执行一次,防止event handler多次调用,如果连续触发就重新计算事件。

Github上找到的关于防抖函数的讨论

vue中的防抖的相关实现

v-model与lazy修饰符

vue提供了输入框数据的双向绑定v-model指令,该指令默认每一次用户的输入都让vue重新计算重新渲染,当用户输入很长一段内容的时候这是极大的渲染负担。因此引入了.lazy修饰符,但.lazy修饰符的局限在于只有当用户focus out才渲染,对于比较小的输入会比较方便,但是大的文本输入情况下不适用。

v-bind:value与event handler

v-bind指令与v-model指令的区别在于,v-bind是实现用户输入流向vue的单向绑定(需要绑定在value上),如果要让vue的数据去流向用户(也就是渲染),需要用到事件处理函数,每一次用户的输入,我都利用事件去update一下,相当于手动实现了v-model的双向绑定。

这样的实现方式与v-model相比,可以更细致化的去定义事件处理函数如何去处理如何去渲染。

1
2
3
4
5
6
<!-- 这里使用了tailwind css -->
<textarea
class="w-full h-full"
:value="text"
@click="update"
></textarea>
1
2
3
4
5
6
7
8
9
10
11
export default {
data() {
return {
text: ""
};
},
methods: {
update(e) {
this.text = e.target.value;
},
}

update延迟调用

前面提到我们不希望每一次用户的输入都导致一次渲染,因此需要对update函数进行一个延迟调用。

1
2
3
update(e) {
setTimeout(() => {this.text = e.target.value;}, 500);
},

以上函数表示,我们希望当用户停止输入经过500ms,vue要去依据输入框中的value值更新vue的data中储存的数据。但是具体去输入的时候,又会发现所有的更新都好像是即时的、instant update,为什么会出现这种情况?因为只要每一次update,都会有一个setTimeout被执行,多次的输入带来的就是多个setTimeout,本质上和上一段中的update函数没区别。

为了解决这个问题,我们在每一次运行setTimeout的时候,都希望vue去check一下是否之前就已经存在了其他的setTimeout,在每一次update前都清理一下之前就有的setTimeout。因此我们需要在data field中定义一个string变量来存储已有的setTimeout。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export default {
data() {
return {
text: "",
timeput: "",
};
},
methods: {
update(e) {
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.text = e.target.value;
}, 500);
},
}

抽象出debounce函数

抽象后的debounce函数是一个工具性质的函数。

1
2
3
4
5
6
7
8
9
10
11
12
methods: {
update(e) {
const task = () => {
this.text = e.target.value;
};
this.debounce(task, 500);
},
debounce(func, wait = 1000) {
clearTimeout(this.timeout);
this.timeout = setTimeout(func, wait);
},
},

使用mixins在page中导入工具函数

vue实例有一个可选的mixins field,可以用于不同的vue实例之间融合merge他们共有的field。如果当前vue实例中已经存在了导入vue实例中的某个变量、方法,那么当前vue实例会覆盖导入vue实例的变量、方法。

vue实例在使用融合后的其他vue实例的变量、方法的时候,直接使用this来调用,仿佛这就是本来定义在当前vue实例中的一样。

详细实现参考vue3-demo3的src/pages/Markdown.vue文件以及src/utilities/mixins/debounce.js文件。

  • 本文标题:防抖函数
  • 本文作者:徐徐
  • 创建时间:2020-12-28 10:00:27
  • 本文链接:https://machacroissant.github.io/2020/12/28/debouce-explaination/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论