JS使用setInterval导致堆溢出

问题描述

使用setInterval运行较长一段时间后出现堆溢出的情况。
在这里插入图片描述
在这里插入图片描述

代码类似于

setInterval(sendHeartbeat, 30000);

function sendHeartbeat() {
    axios.get(url).then(res => {
        console.log("success")
    }).catch(err => {
        console.error(err.message);
    })
}

在一些老机器上运行较长时间就会出现堆溢出,在性能好一点的机器则不会。

猜测出现堆溢出的原因

1、sendHeartbeat方法中有递归调用。

2、sendHeartbeat函数执行时间较长,可能会导致大量的函数调用堆积在内存中,最终导致堆栈溢出。

很显然sendHeartbeat方法是没有递归的,那么只有可能是2的原因了。

解决方案

1、增加定时器的间隔

可以增加定时器的间隔,让方法里面的代码有足够的时间去执行。缺点是不能确定增加间隔之后会不会出现堆溢出。

2、使用setTimeout - 推荐

把上面的代码改造成下面的样子,可以看到我使用了两个setTimeout做成递归的形式替换了setInterval,这样sendHeartbeat方法就会一个个的执行,不会产生堆积。

// 最初的调度
setTimeout(sendHeartbeat, 30000);

function sendHeartbeat() {
    axios.get(url).then(res => {
         console.log("success")
    }).catch(err => {
        console.error(err.message);
    }).finally(() => {
         // 调度下一次执行
        setTimeout(sendHeartbeat, 30000);
    })
}

3、使用定时任务

但是使用定时任务是不能避免任务堆积的问题的。

const cron = require('node-cron');

// 定义定时任务,每30秒执行一次
cron.schedule('*/30 * * * * *', function() {
    sendHeartbeat();
});

function sendHeartbeat() {
    axios.get(url).then(res => {
        console.log("success")
    }).catch(err => {
        console.error(err.message);
    })
}

改进版-状态标记

let running = false; // 用于标记任务是否正在运行

// 定义定时任务,每30秒执行一次
cron.schedule('*/30 * * * * *', function() {
    if (!running) { // 如果任务不在运行中,执行任务
        running = true; // 标记任务为运行中
        sendHeartbeat()
            .then(() => {
                running = false; // 标记任务为未运行
            })
            .catch(err => {
                console.error(err.message);
                running = false; // 标记任务为未运行
            });
    }
});

async function sendHeartbeat() {
   await axios.get(url).then(res => {
        console.log("success")
    }).catch(err => {
        console.error(err.message);
    })
}

总结:

使用setTimeout的优势在于它会等待函数执行完成后再次调用,而不会像setInterval那样按照固定时间间隔调用函数。这使得您可以更好地控制函数之间的间隔,避免函数重叠执行,从而减少了堆积和内存问题的风险。

当函数执行时间不确定或可能较长时,使用setTimeout可以更灵活地调度下一次执行,而不会导致内存问题。此外,使用setTimeout还可以避免setInterval可能出现的时间累积偏差问题。

然而,选择解决方案通常取决于具体的应用场景和需求。如果您需要更复杂的定时任务调度和精确的执行时间,那么使用定时任务(比如node-cron)也是一个不错的选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值