源起:
之前在因为远程办公在家远程办公的时候,自己负责版本任务进度同步的工作,需要在每个工作日下午5点在群里发消息,同步项目进度。这种重复劳动完全可以交给定时服务去做,然后通过webhook推送机器人就好了。
简单实现
第一个想到的可能就是setInterval,每隔1s执行一次函数,判断是否等于目标时间,执行对应的代码,如下:
setInterval 去跑定时任务的问题
时间越长,偏差越大
var date = new Date().getTime()let i = 0let gap = 0var timer = setInterval(function() {i++var later = new Date().getTime()gap += (later - date) / iconsole.log(gap)}, 1000)
setInterval 的运行机制可能和你理解的不太一样
我们每100毫秒调用一次func函数,如果func的执行时间少于100毫秒的话,在遇到下一个100毫秒前就能够执行完:
;
但如果func的执行时间大于100毫秒,该触发下一个func函数时之前的还没有执行完怎么办?答案如下图所示,那么第二个func会在队列(这里的队列是指event loop)中等待,直到第一个函数执行完
;
如果第一个函数的执行时间特别长,在执行的过程中本应触发了许多个func怎么办,那么所有这些应该触发的函数都会进入队列吗?
不,只要发现队列中有一个被执行的函数存在,那么其他的统统忽略。如下图,在第300毫秒和400毫秒处的回调都被抛弃,一旦第一个函数执行完后,接着执行队列中的第二个,即使这个函数已经“过时”很久了。
;
还有一点,虽然你在setInterval的里指定的周期是100毫秒,但它并不能保证两个函数之间调用的间隔一定是一百毫秒。在上面的情况中,如果队列中的第二个函数时在第450毫秒处结束的话,在第500毫秒时,它会继续执行下一轮func,也就是说这之间的间隔只有50毫秒,而非周期100毫秒
setInterval的替代方案
setTimeout 的递归调用
var date = new Date().getTime()let i = 0let gap = 0var timer = setTimeout(function() {i++var later = new Date().getTime()gap += later - (date + i * 1000)console.log(gap)timer = setTimeout(arguments.callee, 1000)}, 1000)
好像还是没有办法解决每秒计时产生的累加精度问题,长时间的定时任务会不会崩溃或者引起内存泄漏的问题。
node-schedule
https://github.com/node-schedule/node-schedule
Node Schedule是用于Node.js的灵活的cron类而非cron类作业调度程序。它允许您使用可选的重复规则来计划作业(任意函数)在特定日期执行。它在任何给定时间仅使用一个计时器(而不是每秒钟/分钟重新评估即将到来的作业)。
cron 表达式语法
http://www.imooc.com/article/73989
带着问题找方法
- node-schedule 如何解决定时服务精度问题
- node-schedule 如何长时间运行
node-schedule 分析
创建一个定时任务
**
schedule.scheduleJob([?name], [?spec], [?method], [?callback])
//example 2pamaramsvar date = new Date(2018, 4, 8, 21, 13, 0);var j = schedule.scheduleJob(date, function(){console.log('Time for tea!');});
这步会创建一个任务(job)保存该任务的回调,同时将该时间假如到定时器中 job.schedule
var job = new Job(name, method, callback);if (job.schedule(spec)) {return job;}
- job 任务的回调和操作
- Invocation 任务的起止时间、重复规则和回调
- prepareNextInvocation 执行队列
- runonDate 只执行定时任务
job.schedule 根据给定时间初始化任务
//每一个具体要执行的任务
job
//定时器和任务的起止时间
Invocation
//长时间timeout
long-timeout
refer:
http://qingbob.com/difference-between-settimeout-setinterval/
