教你写一个小程序定时器管理库

小程序开发


浏览: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)

回来

}

/*设置超时*/