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 相关文章推荐
仿服务器端脚本方式的JS模板实现方法
Apr 27 Javascript
可自己添加html的伪弹出框实现代码
Sep 08 Javascript
javascript创建cookie、读取cookie
Mar 31 Javascript
基于JQuery实现分隔条的功能
Jun 17 Javascript
javascript弹出窗口中增加确定取消按钮
Jun 24 Javascript
浅谈js中test()函数在正则中的使用
Aug 19 Javascript
原生js实现电商侧边导航效果
Jan 19 Javascript
JavaScript中set与get方法用法示例
Aug 15 Javascript
微信小程序实现限制用户转发功能的实例代码
Feb 22 Javascript
vue内置组件component--通过is属性动态渲染组件操作
Jul 28 Javascript
Vue实现开关按钮拖拽效果
Sep 22 Javascript
NestJs使用Mongoose对MongoDB操作的方法
Feb 22 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文件的自动运行方法分析
2016/05/13 PHP
Laravel中日期时间处理包Carbon的简单使用
2017/09/21 PHP
javascript innerText和innerHtml应用
2010/01/28 Javascript
JavaScript函数的4种调用方法详解
2014/04/22 Javascript
jQuery实现拖拽效果插件的方法
2015/03/23 Javascript
jQuery弹出层插件Lightbox_me使用指南
2015/04/21 Javascript
基于Jquery和html5的7款个性化地图插件
2015/11/17 Javascript
js实现横向拖拽导航条功能
2017/02/17 Javascript
JavaScript关联数组用法分析【概念、定义、遍历】
2017/03/15 Javascript
JavaScript中Hoisting详解 (变量提升与函数声明提升)
2017/08/18 Javascript
基于对象合并功能的实现示例
2017/10/10 Javascript
angular2中Http请求原理与用法详解
2018/01/11 Javascript
vue 使某个组件不被 keep-alive 缓存的方法
2018/09/21 Javascript
微信小程序之侧边栏滑动实现过程解析(附完整源码)
2019/08/23 Javascript
关于layui的下拉搜索框异步加载数据的解决方法
2019/09/28 Javascript
小程序自定义模板实现吸顶功能
2020/01/08 Javascript
python执行等待程序直到第二天零点的方法
2015/04/23 Python
构建Python包的五个简单准则简介
2015/06/15 Python
python实时分析日志的一个小脚本分享
2017/05/07 Python
Python跨文件全局变量的实现方法示例
2017/12/10 Python
Python cookbook(字符串与文本)在字符串的开头或结尾处进行文本匹配操作
2018/04/20 Python
使用Python检测文章抄袭及去重算法原理解析
2019/06/14 Python
解决pyqt5中QToolButton无法使用的问题
2019/06/21 Python
用 Python 制作地球仪的方法
2020/04/24 Python
python中用Scrapy实现定时爬虫的实例讲解
2021/01/18 Python
canvas画布实现手写签名效果的示例代码
2019/04/23 HTML / CSS
html5写一个BUI折叠菜单插件的实现方法
2019/09/11 HTML / CSS
《风筝》教学反思
2014/04/10 职场文书
住院医师规范化培训实施方案
2014/06/12 职场文书
心理咨询专业自荐信
2014/07/07 职场文书
领导干部四风问题自我剖析材料
2014/09/25 职场文书
面试感谢信范文
2015/01/22 职场文书
拉贝日记观后感
2015/06/05 职场文书
灵魂歌王观后感
2015/06/17 职场文书
2016年安全生产先进个人事迹材料
2016/02/29 职场文书
SqlServer 垂直分表(减少程序改动)
2021/04/16 SQL Server