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实战之仿淘宝商城左侧导航效果
Apr 12 Javascript
JavaScript中document对象使用详解
Jan 06 Javascript
详解JavaScript的while循环的使用
Jun 03 Javascript
代码分析jQuery四种静态方法使用
Jul 23 Javascript
jquery带动画效果幻灯片特效代码
Aug 27 Javascript
jQuery+PHP+Mysql实现抽奖程序
Apr 12 jQuery
基于three.js编写的一个项目类示例代码
Jan 05 Javascript
用POSTMAN发送JSON格式的POST请求示例
Sep 04 Javascript
浅析Vue 中的 render 函数
Feb 28 Javascript
JavaScript 空间坐标的使用
Aug 19 Javascript
关于Vue Router的10条高级技巧总结
May 06 Vue.js
vue中使用mockjs配置和使用方式
Apr 06 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
html静态页面调用php文件的方法
2014/11/13 PHP
PHP实现图片自动清理的方法
2015/07/08 PHP
程序员的表白神器“520”大声喊出来
2016/05/20 PHP
Laravel定时任务的每秒执行代码
2019/10/22 PHP
php+js实现的拖动滑块验证码验证表单操作示例【附源码下载】
2020/05/27 PHP
javascript innerHTML、outerHTML、innerText、outerText的区别
2008/11/24 Javascript
FLASH 广告之外的链接
2008/12/16 Javascript
jQuery Tips 为AJAX回调函数传递额外参数的方法
2010/12/28 Javascript
jQuery调用WebService的实现代码
2011/06/19 Javascript
js如何设置在iframe框架中指定div不显示
2013/12/04 Javascript
javascript中不等于的代码是什么怎么写
2013/12/29 Javascript
jQuery中:header选择器用法实例
2014/12/29 Javascript
JavaScript继承学习笔记【新手必看】
2016/05/10 Javascript
前端图片懒加载(lazyload)的实现方法(提高用户体验)
2017/08/21 Javascript
js实现鼠标跟随运动效果
2020/08/02 Javascript
JavaScript数组的5种迭代方法
2017/09/29 Javascript
vue实现一拉到底的滑动验证
2019/07/25 Javascript
基于Nuxt.js项目的服务端性能优化与错误检测(容错处理)
2019/10/23 Javascript
jQuery实现获取多选框的值示例
2020/02/07 jQuery
vue实现顶部菜单栏
2020/11/08 Javascript
Map与WeakMap类型在JavaScript中的使用详解
2020/11/18 Javascript
[00:17]DOTA2荣耀之路5:It’s a disastah!
2018/05/28 DOTA
[47:52]DOTA2-DPC中国联赛正赛 iG vs LBZS BO3 第二场 3月4日
2021/03/11 DOTA
python调用fortran模块
2016/04/08 Python
Python利用IPython提高开发效率
2016/08/10 Python
Python实现的生产者、消费者问题完整实例
2018/05/30 Python
python函数map()和partial()的知识点总结
2020/05/26 Python
Skyscanner新西兰:全球领先的旅游搜索网站
2019/08/26 全球购物
机修工岗位职责
2013/11/24 职场文书
银行求职信个人范文
2013/12/16 职场文书
应届毕业生自荐书
2014/06/18 职场文书
党员群众路线对照检查材料
2014/08/31 职场文书
2015年监理个人工作总结
2015/05/23 职场文书
旗帜观后感
2015/06/08 职场文书
基于Python编写简易版的天天跑酷游戏的示例代码
2022/03/23 Python
nginx.conf配置文件结构小结
2022/04/08 Servers