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的asp.net树实现代码
Nov 30 Javascript
使用 JScript 创建 .exe 或 .dll 文件的方法
Jul 13 Javascript
Jquery弹出窗口插件 LeanModal的使用方法
Mar 10 Javascript
JS获取图片实际宽高及根据图片大小进行自适应
Aug 11 Javascript
js微信分享实现代码
Oct 11 Javascript
mui框架移动开发初体验详解
Oct 11 Javascript
使用命令行工具npm新创建一个vue项目的方法
Dec 27 Javascript
jQuery实现的鼠标响应缓冲动画效果示例
Feb 13 jQuery
node 使用 async 控制并发的方法
May 07 Javascript
vue检测对象和数组的变化分析
Jun 30 Javascript
angular的输入和输出的使用方法
Sep 22 Javascript
jQuery实现容器间的元素拖拽功能
Dec 01 jQuery
解决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
咖啡是不是喝了会上瘾?咖啡是必须品吗!
2021/03/04 新手入门
PHP读取MySQL数据代码
2008/06/05 PHP
php连接mssql的一些相关经验及注意事项
2013/02/05 PHP
PHP代码优化的53个细节
2014/03/03 PHP
小程序微信退款功能实现方法详解【基于thinkPHP】
2019/05/05 PHP
jquery $(&quot;#variable&quot;) 循环改变variable的值示例
2014/02/23 Javascript
js获取input长度并根据页面宽度设置其大小及居中对齐
2014/08/22 Javascript
jQuery异步加载数据并添加事件示例
2014/08/24 Javascript
node.js下when.js 的异步编程实践
2014/12/03 Javascript
详解js中构造流程图的核心技术JsPlumb
2015/12/08 Javascript
jQuery代码性能优化的10种方法
2016/06/21 Javascript
Jq通过td获取同行其它列td的方法
2016/10/05 Javascript
js按条件生成随机json:randomjson实现方法
2017/04/07 Javascript
js实现点击切换checkbox背景图片的简单实例
2017/05/08 Javascript
JS实现点击复选框变更DIV显示状态的示例代码
2017/12/18 Javascript
Node.js命令行/批处理中如何更改Linux用户密码浅析
2018/07/22 Javascript
nodejs使用Sequelize框架操作数据库的实现
2020/10/21 NodeJs
vue 数据双向绑定的实现方法
2021/03/04 Vue.js
Python 的 Socket 编程
2015/03/24 Python
python统计文本文件内单词数量的方法
2015/05/30 Python
详解python 发送邮件实例代码
2016/12/22 Python
13个最常用的Python深度学习库介绍
2017/10/28 Python
Python实现的多线程同步与互斥锁功能示例
2017/11/30 Python
Pandas之DataFrame对象的列和索引之间的转化
2019/06/25 Python
Python如何调用JS文件中的函数
2019/08/16 Python
Django 允许局域网中的机器访问你的主机操作
2020/05/13 Python
零基础学python应该从哪里入手
2020/08/11 Python
python3中确保枚举值代码分析
2020/12/02 Python
Shopee马来西亚:随拍即卖,最佳行动电商拍卖平台
2017/06/05 全球购物
iHerb俄罗斯:维生素、补品和天然产品
2020/07/09 全球购物
注塑工厂厂长岗位职责
2013/12/02 职场文书
会计专业自我评价
2014/02/12 职场文书
毕业论文致谢部分怎么写
2015/05/14 职场文书
老生常谈 使用 CSS 实现三角形的技巧(多种方法)
2021/04/13 HTML / CSS
使用Golang的channel交叉打印两个数组的操作
2021/04/29 Golang
WebWorker 封装 JavaScript 沙箱详情
2021/11/02 Javascript