- Hey, 我是 沉浸式趣谈
- 本文首发于【沉浸式趣谈】,我的个人博客 https://yaolifeng.com 也同步更新。
- 转载请在文章开头注明出处和版权信息。
- 如果本文对您有所帮助,请 点赞、评论、转发,支持一下,谢谢!
说实话,作为前端开发者,我们经常需要处理一些定时任务,比如轮询接口、定时刷新数据、自动登出等功能。
过去我总是用 setTimeout 和 setInterval,但这些方案在复杂场景下并不够灵活。
我寻找了更可靠的方案,最终发现了 cron 这个 npm 包,为我的前端项目(特别是 Node.js 环境下运行的那部分)带来了专业级的定时任务能力。
cron 包:不只是个定时器
安装超级简单:
1npm install cron
基础用法也很直观:
1import { CronJob } from 'cron'; 2 3const job = new CronJob( 4 '0 */30 * * * *', // 每30分钟执行一次 5 function () { 6 console.log('刷新用户数据...'); 7 // 这里放刷新数据的代码 8 }, 9 null, // 完成时的回调 10 true, // 是否立即启动 11 'Asia/Shanghai' // 时区 12);
看起来挺简单的,对吧?
但这个小包却能解决前端很多定时任务的痛点。
理解 cron 表达式,这个"魔法公式"
刚开始接触 cron 表达式时,我觉得这简直像某种加密代码。* * * * * * 这六个星号到底代表什么?
在 npm 的 cron 包中,表达式有六个位置(比传统的 cron 多一个),分别是:
秒 分 时 日 月 周
比如 0 0 9 * * 1 表示每周一早上 9 点整执行。
我找到一个特别好用的网站 crontab.guru 来验证表达式。
不过注意,那个网站是 5 位的表达式,少了"秒"这个位置,所以用的时候需要自己在前面加上秒的设置。
月份和星期几还可以用名称来表示,更直观:
1// 每周一、三、五的下午5点执行 2const job = new CronJob('0 0 17 * * mon,wed,fri', function () { 3 console.log('工作日提醒'); 4});
前端开发中的实用场景
作为前端开发者,我在这些场景中发现 cron 特别有用:
1. 在 Next.js/Nuxt.js 等同构应用中刷新数据缓存
1// 每小时刷新一次产品数据缓存 2const cacheRefreshJob = new CronJob( 3 '0 0 * * * *', 4 async function () { 5 try { 6 const newData = await fetchProductData(); 7 updateProductCache(newData); 8 console.log('产品数据缓存已更新'); 9 } catch (error) { 10 console.error('刷新缓存失败:', error); 11 } 12 }, 13 null, 14 true, 15 'Asia/Shanghai' 16);
2. Electron 应用中的定时任务
1// 在 Electron 应用中每5分钟同步一次本地数据到云端 2const syncJob = new CronJob( 3 '0 */5 * * * *', 4 async function () { 5 if (navigator.onLine) { 6 // 检查网络连接 7 try { 8 await syncDataToCloud(); 9 sendNotification('数据已同步'); 10 } catch (err) { 11 console.error('同步失败:', err); 12 } 13 } 14 }, 15 null, 16 true 17);
3. 定时检查用户会话状态
1// 每分钟检查一次用户活动状态,30分钟无活动自动登出 2const sessionCheckJob = new CronJob( 3 '0 * * * * *', 4 function () { 5 const lastActivity = getLastUserActivity(); 6 const now = new Date().getTime(); 7 8 if (now - lastActivity > 30 * 60 * 1000) { 9 console.log('用户30分钟无活动,执行自动登出'); 10 logoutUser(); 11 } 12 }, 13 null, 14 true 15);
踩过的那些坑
使用 cron 包时我踩过几个坑,分享给大家:
- 时区问题:有次我设置了一个定时提醒功能,但总是提前 8 小时触发。一查才发现是因为没设置时区。所以国内用户一定要设置
'Asia/Shanghai'!
1// 这样才会在中国时区的下午6点执行 2const job = new CronJob('0 0 18 * * *', myFunction, null, true, 'Asia/Shanghai');
- this 指向问题:如果你用箭头函数作为回调,会发现无法访问 CronJob 实例的 this。
1// 错误示范 2const job = new CronJob('* * * * * *', () => { 3 console.log('执行任务'); 4 this.stop(); // 这里的 this 不是 job 实例,会报错! 5}); 6 7// 正确做法 8const job = new CronJob('* * * * * *', function () { 9 console.log('执行任务'); 10 this.stop(); // 这样才能正确访问 job 实例 11});
- v3 版本变化:如果你从 v2 升级到 v3,要注意月份索引从 0-11 变成了 1-12。
实战案例:构建一个智能通知系统
这是我在一个电商前端项目中实现的一个功能,用 cron 来管理各种用户通知:
1import { CronJob } from 'cron'; 2import { getUser, getUserPreferences } from './api/user'; 3import { sendNotification } from './utils/notification'; 4 5class NotificationManager { 6 constructor() { 7 this.jobs = []; 8 this.initialize(); 9 } 10 11 initialize() { 12 // 新品上架提醒 - 每天早上9点 13 this.jobs.push( 14 new CronJob( 15 '0 0 9 * * *', 16 async () => { 17 if (!this.shouldSendNotification('newProducts')) return; 18 19 const newProducts = await this.fetchNewProducts(); 20 if (newProducts.length > 0) { 21 sendNotification('新品上架', `今天有${newProducts.length}款新品上架啦!`); 22 } 23 }, 24 null, 25 true, 26 'Asia/Shanghai' 27 ) 28 ); 29 30 // 限时优惠提醒 - 每天中午12点和晚上8点 31 this.jobs.push( 32 new CronJob( 33 '0 0 12,20 * * *', 34 async () => { 35 if (!this.shouldSendNotification('promotions')) return; 36 37 const promotions = await this.fetchActivePromotions(); 38 if (promotions.length > 0) { 39 sendNotification('限时优惠', '有新的限时优惠活动,点击查看详情!'); 40 } 41 }, 42 null, 43 true, 44 'Asia/Shanghai' 45 ) 46 ); 47 48 // 购物车提醒 - 每周五下午5点提醒周末特价 49 this.jobs.push( 50 new CronJob( 51 '0 0 17 * * 5', 52 async () => { 53 if (!this.shouldSendNotification('cartReminder')) return; 54 55 const cartItems = await this.fetchUserCart(); 56 if (cartItems.length > 0) { 57 sendNotification('周末将至', '别忘了查看购物车中的商品,周末特价即将开始!'); 58 } 59 }, 60 null, 61 true, 62 'Asia/Shanghai' 63 ) 64 ); 65 66 console.log('通知系统已初始化'); 67 } 68 69 async shouldSendNotification(type) { 70 const user = getUser(); 71 if (!user) return false; 72 73 const preferences = await getUserPreferences(); 74 return preferences?.[type] === true; 75 } 76 77 // 其他方法... 78 79 stopAll() { 80 this.jobs.forEach(job => job.stop()); 81 console.log('所有通知任务已停止'); 82 } 83} 84 85export const notificationManager = new NotificationManager();
写在最后
作为前端开发者,我们的工作不只是构建漂亮的界面,还需要处理各种复杂的交互和时序逻辑。
npm 的 cron 包为我们提供了一种专业而灵活的方式来处理定时任务,特别是在 Node.js 环境下运行的前端应用(如 SSR 框架、Electron 应用等)。
它让我们能够用简洁的表达式设定复杂的执行计划,帮助我们构建更加智能和用户友好的前端应用。
