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 相关文章推荐
PPK 谈 JavaScript 的 this 关键字 [翻译]
Sep 29 Javascript
THREE.JS入门教程(6)创建自己的全景图实现步骤
Jan 25 Javascript
jquery slibings选取同级其他元素的实现代码
Nov 15 Javascript
jquery取子节点及当前节点属性值的方法
Sep 09 Javascript
js实现点击链接后延迟3秒再跳转的方法
Jun 05 Javascript
论Bootstrap3和Foundation5网格系统的异同
May 16 Javascript
用jQuery实现优酷首页轮播图
Jan 09 Javascript
vue-cli结合Element-ui基于cropper.js封装vue实现图片裁剪组件功能
Mar 01 Javascript
vue服务端渲染缓存应用详解
Sep 12 Javascript
详解小程序用户登录状态检查与更新实例
May 15 Javascript
Vue配置marked链接添加target=&quot;_blank&quot;的方法
Jul 19 Javascript
vue组件实现移动端九宫格转盘抽奖
Oct 16 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版(2)
2006/10/09 PHP
php删除左端与右端空格的方法
2014/11/29 PHP
浅析iis7.5安装配置php环境
2015/05/10 PHP
PHP session垃圾回收机制实例分析
2019/06/28 PHP
js 判断上传文件大小及格式代码
2013/11/13 Javascript
javascript实现json页面分页实例代码
2014/02/20 Javascript
For循环中分号隔开的3部分的执行顺序探讨
2014/05/27 Javascript
原生js仿jquery实现对Ajax的封装
2016/10/04 Javascript
使用BootStrap进行轮播图的制作
2017/01/06 Javascript
div中文字内容溢出常见的解决方法
2017/03/16 Javascript
ES6教程之for循环和Map,Set用法分析
2017/04/10 Javascript
AngularJS中下拉框的高级用法示例
2017/10/11 Javascript
原生JS与jQuery编写简单选项卡
2017/10/30 jQuery
vue使用中的内存泄漏【推荐】
2018/07/10 Javascript
vue form 表单提交后刷新页面的方法
2018/09/04 Javascript
微信小程序日历组件使用方法详解
2018/12/29 Javascript
用node.js写一个jenkins发版脚本
2019/05/21 Javascript
vue 兄弟组件的信息传递的方法实例详解
2019/08/30 Javascript
在vue-cli中引入lodash.js并使用详解
2019/11/13 Javascript
微信小程序实现上拉加载功能
2019/11/20 Javascript
vue keep-alive列表页缓存 详情页返回上一页不刷新,定位到之前位置
2019/11/26 Javascript
js实现倒计时秒杀效果
2020/03/25 Javascript
JavaScript实现多个物体同时运动
2020/03/12 Javascript
vue 虚拟DOM的原理
2020/10/03 Javascript
ES6中的类(Class)示例详解
2020/12/09 Javascript
举例讲解Python设计模式编程中的访问者与观察者模式
2016/01/26 Python
python爬取youtube视频的示例代码
2021/03/03 Python
一款利用css3的鼠标经过动画显示详情特效的实例教程
2014/12/29 HTML / CSS
自我鉴定的范文
2013/10/03 职场文书
初中体育教学反思
2014/01/14 职场文书
ktv周年庆活动方案
2014/08/18 职场文书
抄袭同学作业检讨书1000字
2014/11/20 职场文书
公务员政审材料
2014/12/23 职场文书
2015共产党员公开承诺书
2015/01/22 职场文书
劳动仲裁撤诉申请书
2015/05/18 职场文书
SpringBoot详解整合Redis缓存方法
2022/07/15 Java/Android