做定时任务,一定要用这个神库! - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
Lcode01
V2EX    程序员

做定时任务,一定要用这个神库!

  •  1
    &nbp;
  •   Lcode01
    yaolifeng0629 264 天前 2319 次点击
    这是一个创建于 264 天前的主题,其中的信息可能已经有所发展或是发生改变。
    • Hey, 我是 沉浸式趣谈
    • 本文首发于 [沉浸式趣谈] ,我的个人博客 https://yaolifeng.com 也同步更新。
    • 转载请在文章开头注明出处和版权信息。
    • 如果本文对您有所帮助,请 点赞评论转发,支持一下,谢谢!

    说实话,作为前端开发者,我们经常需要处理一些定时任务,比如轮询接口、定时刷新数据、自动登出等功能。

    过去我总是用 setTimeoutsetInterval,但这些方案在复杂场景下并不够灵活。

    我寻找了更可靠的方案,最终发现了 cron 这个 npm 包,为我的前端项目(特别是 Node.js 环境下运行的那部分)带来了专业级的定时任务能力。

    cron 包:不只是个定时器

    安装超级简单:

    npm install cron 

    基础用法也很直观:

    import { CronJob } from 'cron'; const job = new CronJob( '0 */30 * * * *', // 每 30 分钟执行一次 function () { console.log('刷新用户数据...'); // 这里放刷新数据的代码 }, null, // 完成时的回调 true, // 是否立即启动 'Asia/Shanghai' // 时区 ); 

    看起来挺简单的,对吧?

    但这个小包却能解决前端很多定时任务的痛点。

    理解 cron 表达式,这个"魔法公式"

    刚开始接触 cron 表达式时,我觉得这简直像某种加密代码。* * * * * * 这六个星号到底代表什么?

    在 npm 的 cron 包中,表达式有六个位置(比传统的 cron 多一个),分别是:

    秒 分 时 日 月 周 

    比如 0 0 9 * * 1 表示每周一早上 9 点整执行。

    我找到一个特别好用的网站 crontab.guru 来验证表达式。

    不过注意,那个网站是 5 位的表达式,少了"秒"这个位置,所以用的时候需要自己在前面加上秒的设置。

    月份和星期几还可以用名称来表示,更直观:

    // 每周一、三、五的下午 5 点执行 const job = new CronJob('0 0 17 * * mon,wed,fri', function () { console.log('工作日提醒'); }); 

    前端开发中的实用场景

    作为前端开发者,我在这些场景中发现 cron 特别有用:

    1. 在 Next.js/Nuxt.js 等同构应用中刷新数据缓存

    // 每小时刷新一次产品数据缓存 const cacheRefreshJob = new CronJob( '0 0 * * * *', async function () { try { const newData = await fetchProductData(); updateProductCache(newData); console.log('产品数据缓存已更新'); } catch (error) { console.error('刷新缓存失败:', error); } }, null, true, 'Asia/Shanghai' ); 

    2. Electron 应用中的定时任务

    // 在 Electron 应用中每 5 分钟同步一次本地数据到云端 const syncJob = new CronJob( '0 */5 * * * *', async function () { if (navigator.onLine) { // 检查网络连接 try { await syncDataToCloud(); sendNotification('数据已同步'); } catch (err) { console.error('同步失败:', err); } } }, null, true ); 

    3. 定时检查用户会话状态

    // 每分钟检查一次用户活动状态,30 分钟无活动自动登出 const sessiOnCheckJob= new CronJob( '0 * * * * *', function () { const lastActivity = getLastUserActivity(); const now = new Date().getTime(); if (now - lastActivity > 30 * 60 * 1000) { console.log('用户 30 分钟无活动,执行自动登出'); logoutUser(); } }, null, true ); 

    踩过的那些坑

    使用 cron 包时我踩过几个坑,分享给大家:

    1. 时区问题:有次我设置了一个定时提醒功能,但总是提前 8 小时触发。一查才发现是因为没设置时区。所以国内用户一定要设置 'Asia/Shanghai'
    // 这样才会在中国时区的下午 6 点执行 const job = new CronJob('0 0 18 * * *', myFunction, null, true, 'Asia/Shanghai'); 
    1. this 指向问题:如果你用箭头函数作为回调,会发现无法访问 CronJob 实例的 this 。
    // 错误示范 const job = new CronJob('* * * * * *', () => { console.log('执行任务'); this.stop(); // 这里的 this 不是 job 实例,会报错! }); // 正确做法 const job = new CronJob('* * * * * *', function () { console.log('执行任务'); this.stop(); // 这样才能正确访问 job 实例 }); 
    1. v3 版本变化:如果你从 v2 升级到 v3 ,要注意月份索引从 0-11 变成了 1-12 。

    实战案例:构建一个智能通知系统

    这是我在一个电商前端项目中实现的一个功能,用 cron 来管理各种用户通知:

    import { CronJob } from 'cron'; import { getUser, getUserPreferences } from './api/user'; import { sendNotification } from './utils/notification'; class NotificationManager { constructor() { this.jobs = []; this.initialize(); } initialize() { // 新品上架提醒 - 每天早上 9 点 this.jobs.push( new CronJob( '0 0 9 * * *', async () => { if (!this.shouldSendNotification('newProducts')) return; const newProducts = await this.fetchNewProducts(); if (newProducts.length > 0) { sendNotification('新品上架', `今天有${newProducts.length}款新品上架啦!`); } }, null, true, 'Asia/Shanghai' ) ); // 限时优惠提醒 - 每天中午 12 点和晚上 8 点 this.jobs.push( new CronJob( '0 0 12,20 * * *', async () => { if (!this.shouldSendNotification('promotions')) return; const promotiOns= await this.fetchActivePromotions(); if (promotions.length > 0) { sendNotification('限时优惠', '有新的限时优惠活动,点击查看详情!'); } }, null, true, 'Asia/Shanghai' ) ); // 购物车提醒 - 每周五下午 5 点提醒周末特价 this.jobs.push( new CronJob( '0 0 17 * * 5', async () => { if (!this.shouldSendNotification('cartReminder')) return; const cartItems = await this.fetchUserCart(); if (cartItems.length > 0) { sendNotification('周末将至', '别忘了查看购物车中的商品,周末特价即将开始!'); } }, null, true, 'Asia/Shanghai' ) ); console.log('通知系统已初始化'); } async shouldSendNotification(type) { const user = getUser(); if (!user) return false; const preferences = await getUserPreferences(); return preferences?.[type] === true; } // 其他方法... stopAll() { this.jobs.forEach(job => job.stop()); console.log('所有通知任务已停止'); } } export const notificatiOnManager= new NotificationManager(); 

    写在最后

    作为前端开发者,我们的工作不只是构建漂亮的界面,还需要处理各种复杂的交互和时序逻辑。

    npm 的 cron 包为我们提供了一种专业而灵活的方式来处理定时任务,特别是在 Node.js 环境下运行的前端应用(如 SSR 框架、Electron 应用等)。

    它让我们能够用简洁的表达式设定复杂的执行计划,帮助我们构建更加智能和用户友好的前端应用。

    hkingstu
        1
    hkingstu  
       264 天前
    这个 cron 库看起来 hin 实用
    lisxour
        2
    lisxour  
       264 天前
    我用的是这个,croner
    fov6363
        3
    fov6363  
       264 天前
    如果 node 服务署多个的话,可能要考虑抢占式运行,不了每个服务都运行定时任务有时候会有问题
    Lcode01
        4
    Lcode01  
    OP
       259 天前
    @lisxour 两个都不错,看个人选择
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3210 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 11:09 PVG 19:09 LAX 03:09 JFK 06:09
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86