最近翻阅文档发现在处理边界情况中的程序化的事件侦听器中有一个较好的写法。除了官网中的例子,是否也可以用于定时器中呢?

我在A页面写一个定时器,让他每秒钟打印一个1,然后跳转到b页面,并且如果再跳转回A页面,此时可以看到,定时器依然在执行。这样是非常消耗性能的。上图:

interval1

解决方案1:

首先在data函数里面进行定义定时器名称:

1
2
3
4
5
data() {
return {
timer: null,
};
},

然后这样使用定时器:

1
2
3
4
5
count() { 
this.timer = setInterval(() => {
console.log(1);
}, 1000);
}

最后在beforeDestroy()生命周期内清除定时器:

1
2
3
4
5
6
7
8
9
10
beforeDestroy() {
console.log("定时器即将销毁");
clearInterval(this.timer);
this.timer = null;
},

// 测试用
destroyed() {
console.log("定时器销毁完毕");
}

interval2

方案1也是我们比较常用的方法,但有这里有两个潜在的问题,引用官网的话来说就是:

  • 它需要在这个组件实例中保存这个 timer,如果可以的话最好只有生命周期钩子可以访问到它。这并不算严重的问题,但是它可以被视为杂物。
  • 我们的建立代码独立于我们的清理代码,这使得我们比较难于程序化的清理我们建立的所有东西。

解决方案2:

该方法是通过$once这个事件侦听器在定义完定时器之后的位置来清除定时器。以下是完整代码:

1
2
3
4
5
6
7
8
9
10
11
count() {
this.timer = setInterval(() => {
console.log(1);
}, 1000);

// 通过$once来监听定时器,在beforeDestroy钩子可以被清除。
this.$once("hook:beforeDestroy", () => {
console.log("定时器即将销毁");
clearInterval(this.timer);
});
},

interval3

类似于其他需要在当前页面使用,离开需要销毁的组件(例如一些第三方库的picker组件等等),都可以使用此方式来解决离开后以后在背后运行的问题。

注意:

hook:lifeCycle 的这种通过监听内部事件的方式,并不是 vue 公开暴露的 api,所以存在一定的风险,比如说 vue 的版本更迭,可能会修改这个事件的名称,那么这个时候代码就不能运行了,尽量使用官方暴露的 api,这样官方在版本更新的时候会做出详细的说明。