uniapp中定时任务异步开启时如何防止泄露
setTimeout与setInterval选择
项目里要用到实时刷新,在一个tarbar的页面,几秒一次请求后台数据。这里比较常见做法是setInterval,setInterval会每次定时时间到立即执行一次,不管上一次是否已经执行结束。但是考虑到几个方面:后台接口的限流,ip连接数的限制,网络延迟,担心使用setInterval在极端情况下有大量冗余请求(上一次请求未结束未失败就发起新请求,,请求的执行时间和定时任务间隔时间大量重叠,最终在极短时间内,重复刷新)。所以选用setTimeout,在函数执行结束的回调里,再发起一次setTimeout。比如:
let millSecond = 1000;
function solve(){
...
business code ...
...
setTimeout(solve,1000);
return solve;
}
function start(){
setTimeout(solve(),1000);
}
页面onHide与onShow优化带来的并发问题
为了优化性能以及降低不必要请求,希望在tarbar页面onHide的时候,停止请求,而onShow时继续请求。网上的做法大部分是,保存定时器对象,在对应方法中结束,但是使用了setTimeout这会带来一些并发问题,如下
var _this;
export default {
onLoad() {
_this = this;
},
onShow(){
_this.timer = setTimeout(_this.refresh(),_this.refreshMillSecond);
},
onHide() {
if(_this.timer){
clearTimeout(_this.timer);
}
},
methods: {
refresh(){
uni.request({
...
}).then(res => {
_this.timer = setTimeout(_this.refresh,1000);
}).catch(error => {
_this.timer = setTimeout(_this.refresh,1000);
})
return _this.refresh;
}
}
}
最终测试,这种情况下,可能js也是有线程屏障,导致的结果是,有时onHide并没有关闭掉定时器。主要问题是
_this.timer = setTimeout(_this.refresh,1000);
因为定时器是在请求回调,也就是异步里去重启,这里和onHide关闭有并发问题,如果异步回调在onHide之后执行,就会导致定时任务泄露,没有关闭
优化方法
加入一个全局变量,代表当前定时任务是否还能继续的开关,在onHide时,关闭开关。定时任务每次要开启新的定时任务,必须先读以下开关,确保开关没关闭才能开启,这样通过在定时开始时添加一次检查,不会造成泄露
var _this;
export default {
data(){
return {
timerStart : false
},
},
onLoad() {
_this = this;
},
onShow(){
_this.timerStart = true;
setTimeout(_this.refresh(),_this.refreshMillSecond);
},
onHide() {
_this.timerStart = false;
},
methods: {
refresh(){
if(_this.timerStart){
uni.request({
...
}).then(res => {
_this.timer = setTimeout(_this.refresh,1000);
}).catch(error => {
_this.timer = setTimeout(_this.refresh,1000);
})
}
return _this.refresh;
}
}
}
父子组件问题
现在uniapp里,子组件已经不支持onShow与onHide、onLoad这些页面生命周期事件了。而且
$refs方式在app好像也用不了
网上查阅资料测试后发现,可以通过
this.$emit和this.$on
做全局事件的传递,在父组件中触发事件
//父组件中
export default {
onShow(){
this.$emit('aaaa')
}
}
在子组件中监听
//子组件
export default {
mounted(){
this.$on('aaaa',this.onShow);
},
methods:{
onShow(){}
}
}
在父组件的onShow事件中,调用,触发一个叫aaaa的全局事件给子组件,子组件在mounted函数里,通过this.$on(‘aaaa’,callback)来完成对父组件onShow事件的监听,来调用自己的事件处理,但是有个问题,如果你父组件有多个子组件,这个事件会发送多次(多少个子组件会发送多少次)
上一篇: Flink客户端操作
下一篇: instanceof 运算符