#夏日挑战赛# HarmonyOS - 自定义组件之计时器 原创 精华
作者: 张悦
前言
前段时间项目中遇到了计时器的功能,项目中的计时器其实只是显示功能,数据全是由设备上报的。完成项目后,自己做了一个小的计时器组件,在这个过程中也发现了一些问题。
效果展示
组件直接传入以秒为单位的数据,最终显示如下效果:
实现原理
1. 用setTimeout模拟setInterval的行为
正常情况下,说到计时器首先想到的是使用setInterval,对比setTimeout要去重复调用,setInterval很方便就能实现,如下代码:
但为什么要使用setTimeout呢,查下两个定时器的原理,会发现,创建一个时间间隔为100ms的定时器,setInterval每隔100ms往队列中添加一个事件;100ms后,添加T1定时器代码至队列中,主线程中还有任务在执行,所以等待,some event执行结束后执行T1定时器代码;又过了100ms,T2定时器被添加到队列中,主线程还在执行T1代码,所以等待;又过了100ms,理论上又要往队列里推一个定时器代码,但由于此时T2还在队列中,所以T3不会被添加,结果就是此时被跳过;这里我们可以看到,T1定时器执行结束后马上执行了T2代码,所以并没有达到定时器的效果。
综上所述,setInterval有两个缺点:
- 使用setInterval时,某些间隔会被跳过;
- 可能多个定时器会连续执行;
所以,我们要使用setTimeout模拟setInterval,来规避掉上面的缺点。
2. 用Date.now()获取当前时间,规避浏览器退出再进来造成的计时误差
当我们在使用计时工具的时候,因为一些原因,将浏览器退到后台,再次进来的时候,发现计时器时间不对,感觉刚才退出去的这段时间,计时器是停止状态。针对这个问题,查询会发现,出于节能的考虑, 部分浏览器在进入后台时(或者失去焦点时), 会将 setTimeout 等定时任务暂停,待用户回到浏览器时, 才会重新激活定时任务。
说是暂停,实践操作会发现其实应该说是延迟, 1s 的任务延迟到 2s, 或者更久,总之,计时器计算掉的时间,比实际过去的时间少。解决这个问题,我们可以使用Date.now()记录时间,如下,计算两次计时事件的时间差,来计算每次计时的step。
3. 及时清理定时器
这是容易忽略的一点,我们的组件唯一的一个prop属性就是time,实际的业务场景中,可能会有一些操作改变倒计时的时长,所以我们的组件需要监听time值的改变,来做一些初始化操作,这时候你会发现,当做了2次初始化操作后,我们的代码中会同时存在了2个计时器,时间过了1秒后2个计时器同时触发,对time值做了2次“- 1”操作,所以,我们在初始化时要清除之前的定时器
实现过程
countDown组件hml部分:
countDown组件js部分:
countDown组件css部分:
父组件hml部分:
父组件js部分:
总结
这个计时器组件就是对日常工作的发散,作为一个鸿蒙小白,顺便做一个小小的练习,可能存在一些问题,望大家指正~
更多原创内容请关注:中软国际 HarmonyOS 技术团队
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
赞,很实用的知识!
收藏收藏