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 数值项目的格式化函数代码
May 14 Javascript
Javascript(AJAX)解析XML的代码(兼容FIREFOX/IE)
Jul 11 Javascript
jquery attr 设定src中含有&amp;(宏)符号问题的解决方法
Jul 26 Javascript
一款jquery特效编写的大度宽屏焦点图切换特效的实例代码
Aug 05 Javascript
浅析javascript中function 的 length 属性
May 27 Javascript
js使用DOM设置单选按钮、复选框及下拉菜单的方法
Jan 20 Javascript
js实现人才网站职位选择功能的方法
Aug 14 Javascript
原生JS改变透明度实现轮播效果
Mar 24 Javascript
js input输入百分号保存数据库失败的解决方法
May 26 Javascript
Angular使用cli生成自定义文件、组件的方法
Sep 04 Javascript
微信小程序textarea层级过高(盖住其他元素)问题的解决办法
Mar 04 Javascript
Node.js + express基本用法教程
Mar 14 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个人网站架设连环讲(四)
2006/10/09 PHP
php引用计数器进行垃圾收集机制介绍
2012/09/19 PHP
解析php中用PHPMailer来发送邮件的示例(126.com的例子)
2013/06/24 PHP
PHP imagegrabscreen和imagegrabwindow(截取网站缩略图)的实例代码
2013/11/07 PHP
PHP的Laravel框架中使用消息队列queue及异步队列的方法
2016/03/21 PHP
php HTML无刷新提交表单
2016/04/05 PHP
代码精简的可以实现元素圆角的js函数
2007/07/21 Javascript
锋利的jQuery 第三章章节总结的例子
2010/03/23 Javascript
23个Javascript弹出窗口特效整理
2011/02/25 Javascript
jQuery实现表格行上移下移和置顶的方法
2015/05/22 Javascript
简介AngularJS的视图功能应用
2015/06/17 Javascript
javascript去掉代码里面的注释
2015/07/24 Javascript
微信JS-SDK坐标位置如何转换为百度地图坐标
2016/07/04 Javascript
任意Json转成无序列表的方法示例
2016/12/09 Javascript
AngularJS使用ng-repeat遍历二维数组元素的方法详解
2017/11/11 Javascript
jQuery实现的鼠标响应缓冲动画效果示例
2018/02/13 jQuery
this在vue和小程序中的使用详解
2019/01/28 Javascript
推荐15个最好用的JavaScript代码压缩工具
2019/02/13 Javascript
seajs和requirejs模块化简单案例分析
2019/08/26 Javascript
[00:53]2015国际邀请赛 中国区预选赛一触即发
2015/05/14 DOTA
[04:40]2016个国际邀请赛中国区预选赛场地——华西村观战指南
2016/06/25 DOTA
python3利用venv配置虚拟环境及过程中的小问题小结
2018/08/01 Python
Python实现DDos攻击实例详解
2019/02/02 Python
详解使用Python下载文件的几种方法
2019/10/13 Python
使用pytorch完成kaggle猫狗图像识别方式
2020/01/10 Python
Tensorflow实现多GPU并行方式
2020/02/03 Python
python数据预处理 :数据共线性处理详解
2020/02/24 Python
python matplotlib imshow热图坐标替换/映射实例
2020/03/14 Python
python openpyxl模块的使用详解
2021/02/25 Python
python lambda的使用详解
2021/02/26 Python
英国外籍人士的在线超市:British Corner Shop
2019/06/03 全球购物
企业党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
大学升旗仪式主持词
2015/07/04 职场文书
2015秋季开学典礼演讲稿
2015/07/16 职场文书
pycharm安装深度学习pytorch的d2l包失败问题解决
2022/03/25 Python
详细介绍python操作RabbitMq
2022/04/12 Python