NodeJs之定时器与队列
一,介绍与需求
1.1,介绍
定时任务(node-schedule),是针对Node.js的一种灵活的cron-like和not-cron-like作业调度程序。它允许您使用可选的递归规则将作业(任意函数)安排在特定日期执行。它在任何给定的时间只使用一个计时器(而不是每秒钟/分钟重新评估即将到来的作业)。
Async是一个实用模块,它为异步JavaScript提供了直接、强大的功能。async流程控制器--queue(队列),queue流程控制器是一个并行的流程控制器,但是它与parallel的区别在于queue可以控制一次执行几个函数,而parallel只是让所有函数并行执行.
1.2,需求
实际开发项目中,会遇到很多定时任务的工作。比如:定时导出某些数据、定时发送消息或邮件给用户、定时备份什么类型的文件等等。在当时给用户发送消息时,可能要发送的用户就不只有一两个,二是多个,这是可能就会用到队列顺序执行。
二,定时器
第一步:安装node-schedule
1 npm install node-schedule --save
第二步:封装定时器模块
1 const schedule = require('node-schedule');//定时器 2 const nodeTimer = {}; 3 let cancelTimer = '' 4 /** 5 *Cron风格定时器/对象文本语法定时器 6 * @param executionTime :定时器字符串'30 * * * * *'/定时器对象{hour: 16, minute: 11, dayOfWeek: 1} 7 * @param callback :回调函数 8 */ 9 nodeTimer.scheduleTimer = (executionTime = '30 * * * * *', callback) => { 10 // 每分钟的第30秒触发: '30 * * * * *' 11 // 每小时的1分30秒触发 :'30 1 * * * *' 12 // 每天的凌晨1点1分30秒触发 :'30 1 1 * * *' 13 // 每月的1日1点1分30秒触发 :'30 1 1 1 * *' 14 // 2016年的1月1日1点1分30秒触发 :'30 1 1 1 2016 *' 15 // 每周1的1点1分30秒触发 :'30 1 1 * * 1' 16 17 cancelTimer = schedule.scheduleJob(executionTime, () => { 18 if (typeof callback === 'function') { 19 callback() 20 } 21 }); 22 23 } 24 module.exports = nodeTimer;
第三步:调用
在回调函数中写入要执行的任务代码,一个定时器就完成了!
引入定时器模块:
1 const nodeTimer = require('./node_timer.js');
1,Cron风格定时器
规则参数讲解 *代表通配符
* * * * * * ┬ ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ │ │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun) │ │ │ │ └───── month (1 - 12) │ │ │ └────────── day of month (1 - 31) │ │ └─────────────── hour (0 - 23) │ └──────────────────── minute (0 - 59) └───────────────────────── second (0 - 59, OPTIONAL)
6个占位符从左到右分别代表:秒、分、时、日、月、周几
*
表示通配符,匹配任意,当秒是*
时,表示任意秒数都触发,其它类推
1 // 每分钟的第30秒触发: '30 * * * * *' 2 // 每小时的1分30秒触发 :'30 1 * * * *' 3 // 每天的凌晨1点1分30秒触发 :'30 1 1 * * *' 4 // 每月的1日1点1分30秒触发 :'30 1 1 1 * *' 5 // 2016年的1月1日1点1分30秒触发 :'30 1 1 1 2016 *' 6 // 每周1的1点1分30秒触发 :'30 1 1 * * 1' 7 // 每分钟的1-10秒都会触发,其它通配符依次类推 :'1-10 * * * * *'
调用定时器:
1 nodeTimer.scheduleTimer('30 * * * * *',function(err){ 2 if(!err){ 3 console.log('scheduleTimer:' + new Date()); 4 } 5 });
效果:
2、对象文本语法定时器
second (0-59)
minute (0-59)
hour (0-23)
date (1-31)
month (0-11)
year
dayOfWeek (0-6) Starting with Sunday
1 //每周一的下午15:03:30触发,其它组合可以根据我代码中的注释参数名自由组合 2 nodeTimer.scheduleTimer({hour: 15, minute: 3, second: 30},function(err){ 3 if(!err){ 4 console.log('scheduleTimer:' + new Date()); 5 } 6 });
效果:
3、基于日期的定时器
1 var date = new Date(2019, 01, 07, 15, 03, 30); 2 nodeTimer.scheduleTimer(date,function(err){ 3 if(!err){ 4 console.log('scheduleTimer:' + new Date()); 5 } 6 });
4、递归规则定时器
参数与对象文本语法定时器的参数类似
1 var rule = new schedule.RecurrenceRule(); 2 rule.dayOfWeek = [0, new schedule.Range(4, 6)];//每周四,周五,周六执行 3 rule.hour = 15; 4 rule.minute = 0; 5 nodeTimer.scheduleTimer(rule,function(err){ 6 if(!err){ 7 console.log('scheduleTimer:' + new Date()); 8 } 9 });
5、取消定时器
1 // 取消定时器 2 // 调用 定时器对象的cancl()方法即可 3 nodeTimer.scheduleCancel = () => { 4 // 定时器取消 5 cancelTimer.cancel(); 6 console.log('定时器成功取消'); 7 }
调用:
1 nodeTimer.scheduleCancel()
效果:
三,队列
第一步:安装async
1 npm install --save async
第二步:封装方法
queue相当于一个加强版的parallel,主要是限制了worker数量,不再一次性全部执行。当worker数量不够用时,新加入的任务将会排队等候,直到有新的worker可用。
该函数有多个点可供回调,如worker用完时、无等候任务时、全部执行完时等。
1 const async = require('async'); 2 /** 3 *队列 4 * @param obj :obj对象 包含执行时间 5 * @param callback :回调函数 6 */ 7 const nodeQueue = async.queue(function (obj, callback) { 8 setTimeout(function () { 9 // 需要执行的代码的回调函数 10 if(typeof callback==='function'){ 11 callback(); 12 } 13 }, obj.time) 14 }, 1) 15 16 // worker数量将用完时,会调用saturated函数 17 nodeQueue.saturated = function() { 18 console.log('all workers to be used'); 19 } 20 21 // 当最后一个任务交给worker执行时,会调用empty函数 22 nodeQueue.empty = function() { 23 console.log('no more tasks wating'); 24 } 25 26 // 当所有任务都执行完时,会调用drain函数 27 nodeQueue.drain = function() { 28 console.log('all tasks have been processed'); 29 } 30 module.exports = nodeQueue;
第三步:调用方法
1 const nodeQueue = require('./node_queue.js'); 2 for (let i = 0; i < 10; i++) { 3 nodeQueue.push({ name: 1, time: 2000 }, function (err) { 4 console.log('队列执行错误信息==',err); 5 if(!err){ 6 // 需要执行的代码或函数 7 console.log('需要执行的代码或函数第',i+1,'个') 8 } 9 }) 10 };
效果: