Vue中如何清除一个定时器
一般我们在清除定时器的时候是这样写的:
<script> export default { data() { return { timer:null, } }, mounted() { }, methods: { openTimer(){ this.timer = setInterval(()=>{ console.log("setInterval"); },1000) } }, beforeDestroy () { clearInterval(this.timer); this.timer = null; } } </script>
- 开启定时器和清除定时器的代码分散开在两个地方,有损可读性/维护,这使得我们比较难于程序化地清理我们建立的东西。
- timer 被定义在 data 里,实际上 timer 不需要什么响应式操作,定义在 data 里是没必要的,反而造成性能浪费
优化后:
<script> export default { data() { return { } }, mounted() { let timer = setInterval(()=>{ console.log("setInterval"); },1000) // 一次性侦听一个事件,只执行一次 this.$once("hook:beforeDestroy", ()=>{ clearInterval(timer); timer = null; }) } } </script>
衍生问题:beforeDestroy 没有触发?
在后台系统中,我们常常会设置页面缓存,而当路由被 keep-alive 缓存时是不走 beforeDestroy 生命周期的,所以有些小伙伴以为在 beforeDestroy 清除定时器就完事了,甚至都没有检查一下,实际上定时器并没有被清除掉。知道了原因也就好解决了,借助 activated 和 deactivated 这两个生钩子
<script> export default { data() { return { } }, mounted() { let timer = setInterval(()=>{ console.log("setInterval"); },1000) // activated 被 keep-alive 缓存的组件激活时调用。 this.$on("hook:activated", () => { if (timer === null) { // 避免重复开启定时器 timer = setInterval(()=>{ console.log("setInterval"); },1000) } }) // deactivated 被 keep-alive 缓存的组件失活时调用 this.$on("hook:deactivated", ()=>{ clearInterval(timer); timer = null; }) } } </script>
这里需要注意一下,由于缓存原因,所以需要用 $on 而不是 $once,不然执行一次后就不会再触发了。