vue 实现setInterval 创建和销毁实例


Posted in Javascript onJuly 21, 2020

问题

setInterval 是间隔调用,与之类似的还有 setTimeout。这两个 API 通常用来做 ajax 短连接轮询数据。

比如有一个 logs.vue 是用来展示某个正在执行的进程产生的日志:

<template>
 <div>
 <p v-for="item in logList" :key="item.time">
  <span>{{"[" + item.time + "]"}}</span>
  <span>{{ item.log }}</span>
 </p>
 </div>
</template>
<script>
 import { Component, Vue, Watch, Prop, Emit } from 'vue-property-decorator'
 import { getLogList } from './api'
 @Component({})
 export default class extends Vue {
 logList = []
 timer = null
 mounted(){
  this.getData()
 }
 async getData(){
  let r = await getLogList()
  if(r && r.logList){
  this.logList = r.logList
  }
  this.timer = setTimeout(()=>{
  console.log(this.timer);
  this.getData()
  }, 1000)
 }
 beforeDestory(){
  clearTimeout(this.timer)
  this.timer = null;
 }
 }
</script>

这段代码看上去没啥问题,但是测试的时候你会发现,有时候路由已经跳转了,获取进程日志的接口依然在不断调用,甚至,有时候接口调用速度非常快,一秒可能有好几个请求。

分析

beforeDestory 是组件销毁前的生命周期的钩子,这个钩子函数一定会调用,但是能不能彻底销毁 setTimeout 呢?答案是不能。

打开控制台就能看到不断打印出来的 id

vue 实现setInterval 创建和销毁实例

这是因为,每次使用 clearTimeout 清除掉的是上一次的 id, 而不是本次正要执行的,这种情况,对于使用 setInterval 也是一样的。

根本原因在于,每次调用 getData, this.timer 是在不断的被赋予新的值,而不是一成不变的。

在以前的原生 js 中,我们通常这样写:

var timer = null
function init(){
 timer = setInterval(function(){
 getData()
 })
}
function getData(){}
window.onload = init
window.onunload = function(){
 clearInterval(timer)
}

由于上面的 timer 始终保持一个值,所以这里的清除是有效的

解决

vue 提供了 程序化的事件侦听器 来处理这类边界情况

按照文档的说法,我们的代码可以这样来更改

<script>
 import { Component, Vue, Watch, Prop, Emit } from 'vue-property-decorator'
 import { getLogList } from './api'
 @Component({})
 export default class extends Vue {
 logList = []
 // timer = null
 mounted(){
  this.getData()
 }
 async getData(){
  let r = await getLogList()
  if(r && r.logList){
  this.logList = r.logList
  }
  const timer = setTimeout(()=>{
  this.getData()
  }, 1000)
  this.$once('hook:beforeDestroy', function () {
    clearTimeout(timer)
  })
 }
 }
</script>

这样写,还解决了两个潜在问题

在组件实例中保存这个 timer,最好只有生命周期钩子有访问它的权限。但是实例中的 timer 会视为杂物

如果建立代码独立于清理代码,会使得我们比较难于程序化地清理所建立的东西

如果你是在项目中引入了 ts,那么可能会导致在组件销毁的时候,定时器不能成功清除,这时候,你需要使用

const timer = window.setTimeout(()=>{
 this.getData()
}, 1000)
this.$once('hook:beforeDestroy', function () {
  window.clearTimeout(timer)
})

如果你漏掉了其中一个 window,那么很可能会遇上类似的 ts 报错:Type 'Timer' is not assignable to type 'number',这是因为 node typings

It seems like you are using node typings which override setInterval() as something that returns NodeJS.Timer. If you're running in the browser, it doesn't make a whole lot of sense to use these,

结论

我们可以通过 程序化的事件侦听器 来监听销毁我们创建的任何代码示例

除了 setTimeout 和 setInterval ,通常还有一些第三方库的对象示例,如 timePicker,datePicker,echarts图表等。

mounted: function () {
 // Pikaday 是一个第三方日期选择器的库
  var picker = new Pikaday({
   field: this.$refs.input,
   format: 'YYYY-MM-DD'
  })
 // 在组件被销毁之前,也销毁这个日期选择器。
  this.$once('hook:beforeDestroy', function () {
   picker.destroy()
  })
}

以上这篇vue 实现setInterval 创建和销毁实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
说说掌握JavaScript语言的思想前提想学习js的朋友可以看看
Apr 01 Javascript
JavaScript Konami Code 实现代码
Jul 29 Javascript
js自定义事件及事件交互原理概述(一)
Feb 01 Javascript
JS获取url链接字符串 location.href
Dec 23 Javascript
jquery实现漫天雪花飞舞的圣诞祝福雪花效果代码分享
Aug 20 Javascript
购物车前端开发(jQuery和bootstrap3)
Aug 27 Javascript
关于Function中的bind()示例详解
Dec 02 Javascript
jQuery实现简单的计时器功能实例分析
Aug 29 jQuery
微信小程序里引入SVG矢量图标的方法
Sep 20 Javascript
VUE 动态组件的应用案例分析
Dec 02 Javascript
VSCode写vue项目一键生成.vue模版,修改定义其他模板的方法
Apr 17 Javascript
如何vue使用el-table遍历循环表头和表体数据
Apr 26 Vue.js
解决vue.js中settimeout遇到的问题(时间参数短效果不稳定)
Jul 21 #Javascript
Vue清除定时器setInterval优化方案分享
Jul 21 #Javascript
解决vue 使用setTimeout,离开当前路由setTimeout未销毁的问题
Jul 21 #Javascript
JavaScript undefined及null区别实例解析
Jul 21 #Javascript
Vue 解决父组件跳转子路由后当前导航active样式消失问题
Jul 21 #Javascript
Vue切换组件实现返回后不重置数据,保留历史设置操作
Jul 21 #Javascript
vue 实现tab切换保持数据状态
Jul 21 #Javascript
You might like
PHP STRING 陷阱原理说明
2010/07/24 PHP
php高级编程-函数-郑阿奇
2011/07/04 PHP
php判断上传的Excel文件中是否有图片及PHPExcel库认识
2013/01/11 PHP
PHP中使用循环实现的金字塔图形
2014/11/08 PHP
PHP排序二叉树基本功能实现方法示例
2018/05/26 PHP
Centos7安装swoole扩展操作示例
2020/03/26 PHP
Jquery从头学起第四讲 jquery入门教程
2010/08/01 Javascript
JavaScript访问样式表代码
2010/10/15 Javascript
JS连连看源码完美注释版(推荐)
2013/12/09 Javascript
jquery选择器之属性过滤选择器详解
2014/01/27 Javascript
javascript定义变量时有var和没有var的区别探讨
2014/07/21 Javascript
form.submit()不能提交表单的错误原因及解决方法
2014/10/13 Javascript
jQuery实现发送验证码并60秒倒计时功能
2016/11/25 Javascript
JavaScript版经典游戏之扫雷游戏完整示例【附demo源码下载】
2016/12/12 Javascript
微信小程序 商城开发(ecshop )简单实例
2017/04/07 Javascript
mui框架 页面无法滚动的解决方法(推荐)
2018/01/25 Javascript
JS 使用 window对象的print方法实现分页打印功能
2018/05/16 Javascript
jQuery表单元素过滤选择器用法实例分析
2019/02/20 jQuery
webpack结合express实现自动刷新的方法
2019/05/07 Javascript
Vue常用传值方式、父传子、子传父及非父子实例分析
2020/02/24 Javascript
js实现轮播图特效
2020/05/28 Javascript
JavaScript this指向相关原理及实例解析
2020/07/10 Javascript
Python while、for、生成器、列表推导等语句的执行效率测试
2015/06/03 Python
详解python 字符串和日期之间转换 StringAndDate
2017/05/04 Python
对python当中不在本路径的py文件的引用详解
2018/12/15 Python
详解python 爬取12306验证码
2019/05/10 Python
Django中提供的6种缓存方式详解
2019/08/05 Python
python 接口实现 供第三方调用的例子
2019/08/13 Python
Python常用数据类型之间的转换总结
2019/09/06 Python
使用HTML5和CSS3表单验证功能
2017/05/05 HTML / CSS
师德师风剖析材料
2014/09/30 职场文书
后进生评语大全
2015/01/04 职场文书
委托书范本格式
2019/04/18 职场文书
如何解决springcloud feign 首次调用100%失败的问题
2021/06/23 Java/Android
英镑符号 £
2022/02/17 杂记
JavaScript实现两个数组的交集
2022/03/25 Javascript