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 相关文章推荐
jQuery powerFloat万能浮动层下拉层插件使用介绍
Dec 27 Javascript
javascript操作表格排序实例分析
May 06 Javascript
js正则表达式中exec用法实例
Jul 23 Javascript
javascript实现超炫的向上滑行菜单实例
Aug 03 Javascript
JS验证邮件地址格式方法小结
Dec 01 Javascript
Node.js使用orm2进行update操作时关联字段无法修改的解决方法
Jun 13 Javascript
webpack 单独打包指定JS文件的方法
Feb 22 Javascript
浅谈vuepress 踩坑记
Apr 18 Javascript
KnockoutJS数组比较算法实例详解
Nov 25 Javascript
js判断密码强度的方法
Mar 18 Javascript
vue通过过滤器实现数据格式化
Jul 20 Javascript
vue 如何从单页应用改造成多页应用
Oct 23 Javascript
解决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求正负数数组中连续元素最大值示例
2014/04/11 PHP
一个不易被发现的PHP后门代码解析
2014/07/05 PHP
PHP 下载文件时如何自动添加bom头及解释BOM头和去掉bom头的方法
2016/01/04 PHP
PHP中散列密码的安全性分析
2019/07/26 PHP
javascript静态的url如何传递
2007/05/03 Javascript
javascript 流畅动画实现原理
2009/09/08 Javascript
jquery关于页面焦点的定位(文本框获取焦点时改变样式 )
2010/09/10 Javascript
通过js动态操作table(新增,删除相关列信息)
2012/05/23 Javascript
定义JavaScript二维数组采用定义数组的数组来实现
2012/12/09 Javascript
浅谈javascript中this在事件中的应用
2015/02/15 Javascript
几种二级联动案例(jQuery\Array\Ajax php)
2016/08/13 Javascript
分分钟玩转Vue.js组件
2016/10/25 Javascript
微信小程序获取音频时长与实时获取播放进度问题
2018/08/28 Javascript
js实现无缝滚动双图切换效果
2019/07/09 Javascript
JavaScript Array对象使用方法解析
2019/09/24 Javascript
Python正则表达式的使用范例详解
2014/08/08 Python
实例探究Python以并发方式编写高性能端口扫描器的方法
2016/06/14 Python
50行Python代码实现人脸检测功能
2018/01/23 Python
Python判断一个三位数是否为水仙花数的示例
2018/11/13 Python
Python实现子类调用父类的初始化实例
2020/03/12 Python
Python定义函数实现累计求和操作
2020/05/03 Python
Django 解决model 反向引用中的related_name问题
2020/05/19 Python
python 实现rolling和apply函数的向下取值操作
2020/06/08 Python
Python使用socket_TCP实现小文件下载功能
2020/10/09 Python
Android本地应用打开方法——通过html5写连接
2016/03/11 HTML / CSS
amazeui模态框弹出后立马消失并刷新页面
2020/08/19 HTML / CSS
巴西体育用品商店:Lojão dos Esportes
2018/07/21 全球购物
The North Face北面德国官网:美国著名户外品牌
2018/12/12 全球购物
Fanatics法国官网:美国体育电商
2019/08/27 全球购物
超市仓管员岗位职责
2014/04/07 职场文书
学生自我评语大全
2014/04/18 职场文书
民族团结好少年事迹材料
2014/08/19 职场文书
党性锻炼的心得体会
2014/09/03 职场文书
出纳工作检讨书
2014/10/18 职场文书
使用ICOM IC-R9500接收机同时测评十台收音机中波接收性能
2022/05/10 无线电
Redis 报错 error:NOAUTH Authentication required
2022/05/15 Redis