教你写一个小程序定时器管理库
小程序开发
浏览:557 次

作者:托曼·阿吉
出身背景
托曼是一名小程序开发人员。他想在小程序中实现秒的倒计时。因此,他不假思索地写了以下代码:
第页({
init:函数(){
clearInterval(this.timer)
这计时器=设置间隔(()=>{
//倒计时计算逻辑
console.log('setInterval')
})
},
})
然而,当Bumpman发现页面隐藏在后台时,计时器仍在运行。因此,对凹凸曼恩进行了优化。页面显示时运行,隐藏时暂停。
第页({
onShow:函数(){
if(this.timer){
这计时器=设置间隔(()=>{
//倒计时计算逻辑
console.log('setInterval')
})
}
},
onHide:函数(){
clearInterval(this.timer)
},
init:函数(){
clearInterval(this.timer)
这计时器=设置间隔(()=>{
//倒计时计算逻辑
console.log('setInterval')
})
},
})
这个问题似乎已经解决了。正当拓曼开心地搓着小手,暗自高兴时,他突然发现小程序页面被破坏时不一定调用onHide函数,所以计时器无法清理?这可能会导致内存泄漏。托曼想了一会儿。事实上,解决这个问题并不难。您也可以在页面处于“卸载”状态时清除计时器一次。
第页({
...

onUnload:函数(){
clearInterval(this.timer)
},
})
这个问题已经解决,但我们可以发现,在小程序中使用计时器需要非常小心,不小心会导致内存泄漏。
后台累积的计时器越多,小程序就越卡顿,功耗也就越大,最终导致程序卡顿甚至崩溃。特别是对于团队开发的项目,很难确保每个成员都正确地清理计时器。因此,编写一个定时器管理库来管理定时器的生命周期将是有益的。
思想整理
首先,让我们设计计时器的API规范。计时器离本地API越近越好。这样,开发人员可以毫不费力地替换它。
函数$setTimeout(fn,timeout,…arg){}
函数$setInterval(fn,timeout,…arg){}
函数$clearTimeout(id){}
函数$clearInterval(id){}
接下来,我们将主要解决以下两个问题
如何暂停和恢复计时器
如何使开发人员不需要在生命周期函数中处理计时器
如何暂停和恢复计时器
想法如下:
保存计时器功能参数,并在计时器恢复时重新创建它们
由于重新创建计时器时计时器ID将不同,因此需要自定义全局唯一ID来标识计时器
隐藏时记录计时器的剩余倒计时时间,恢复时用剩余时间重新创建计时器
首先,我们需要定义一个Timer类。计时器对象将存储计时器功能参数。代码如下
类计时器{
静态计数=0
/**
*施工单位
*@param{Boolean}isInterval是否为setInterval
*@param{Function}fn回调函数
*@param{Number}timeout计时器执行间隔
*@param{…any}参数计时器的其他参数
*/
构造函数(isInterval=false,fn=()=>{},超时=0,…arg){
这id=++计时器。计数//计时器增量ID
这fn=fn
这timeout=超时
这RestTime=timeout//剩余计时器时间
这isInterval=isInterval

这arg=参数
}
}
//创建计时器
函数$setTimeout(fn,timeout,…arg){
常量计时器=新计时器(false,fn,timeout,arg)
返回计时器.id
}
接下来,我们将暂停并恢复计时器。实施思路如下:
启动计时器,调用本机API创建计时器,并记录开始计时时间戳。
暂停计时器,清除计时器并计算循环计时的剩余时间。
恢复计时器,重新记录开始计时时间戳,并使用剩余时间创建计时器。
代码如下:
类计时器{
构造函数(isInterval=false,fn=()=>{},超时=0,…arg){
这id=++计时器。计数//计时器增量ID
这fn=fn
这timeout=超时
这RestTime=timeout//剩余计时器时间
这isInterval=isInterval
这arg=参数
}
/**
*启动或恢复计时器
*/
启动(){
这startTime=+新日期()
if(this.isInterval){
/*设置间隔*/
常量cb=(…arg)=>{
此.fn(…arg)
/*如果timerId为空,则表示clearInterval*/
如果(this.timerId)这个。timerId=设置超时(cb,this.timeout,…this.arg)
}
这timerId=setTimeout(cb,this.restTime,…this.arg)
回来

}
/*设置超时*/