You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Node.js中每30秒执行调用axios的函数并解决内存溢出问题

问题原因说明

  1. 你写的同步while(true)死循环会直接阻塞Node.js的单线程事件循环,所有异步请求、定时器操作都无法被调度,同时循环会不断生成调用栈占用内存,最终触发堆内存溢出。
  2. 之前用setInterval出问题的原因是:它不会等待上一次mvcAppointmentSearch内部的所有异步请求处理完成,每30秒就强制触发新的执行,导致请求堆积、cheerio加载的DOM对象无法被垃圾回收,内存占用持续上涨最终溢出。

可行的解决方案

我们用异步循环+等待上轮执行完成再间隔的逻辑实现,既保证每轮请求都处理完成再等30秒执行下一轮,也不会出现请求堆积问题:

1. 先修改原有异步函数的逻辑,确保可以等待执行完成

const express = require('express');
const request = require('request-promise');
const cheerio = require('cheerio');
const axios = require('axios');
const cssSelect = require('css-select');
const open = require('open');

const mvcUrl = 'https://telegov.njportal.com/njmvc/AppointmentWizard/14/';
const mvcLocation = ['Edison', 'Rahway', 'SouthPlainfield'];
const mvcLocationNumber = ['163'];
const requiredMonths = ['September', 'October'];

// 原callUrl保持async,天然返回Promise
const callUrl = async (url, locationNumberIndex) => {
  try {
    const response = await axios.get(url);
    getData(response.data, locationNumberIndex);
  } catch (err) {
    console.log(err);
  }
};

// 修改mvcAppointmentSearch为async,等待所有地址请求完成
const mvcAppointmentSearch = async () => {
  // 收集所有请求的Promise,用Promise.all等待全部执行完成
  const requestTasks = [];
  for (let i = 0; i < mvcLocationNumber.length; i++) {
    const currentUrl = mvcUrl + mvcLocationNumber[i];
    console.log(mvcLocationNumber[i]);
    requestTasks.push(callUrl(currentUrl, i));
  }
  await Promise.all(requestTasks);
};

const getData = (html, locationNumberIndex) => {
  let data = [];
  let $ = cheerio.load(html);

  $.prototype.exists = function (selector) {
    return this.find(selector).length > 0;
  };

  const checkerLength = $('div').exists('.alert-danger');

  console.log(checkerLength);
  if (checkerLength) {
    console.log(
      `No appointment available in ${mvcLocation[locationNumberIndex]}`
    );
  } else {
    const dateString = $('.control-label').text();
    const availableMonth = dateString.trim().split(' ')[7];
    const exactDateAvailability = dateString.slice(24, -1);
    console.log(availableMonth);
    if (requiredMonths.includes(availableMonth)) {
      console.log('Hurray there is an appointment available');
      const message = `Appointment available for the location ${mvcLocation[locationNumberIndex]} on ${exactDateAvailability}`;
      open(`${mvcUrl + mvcLocationNumber[locationNumberIndex]}`);
      console.log(message);
    } else {
      console.log('required Month is not available still searching');
    }
  }
};

2. 替换原有同步死循环,实现异步间隔执行

// 封装sleep工具函数,返回指定毫秒后resolve的Promise
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

// 异步循环函数
const startLoop = async () => {
  while (true) {
    try {
      console.log('开始执行本轮查询');
      // 等待本轮所有查询执行完成
      await mvcAppointmentSearch();
      console.log('本轮查询完成,等待30秒后执行下一轮');
      // 等待30秒
      await sleep(30 * 1000);
    } catch (err) {
      console.log(`执行出错:${err}`);
      // 出错也等30秒再重试,避免出错后高频循环
      await sleep(30 * 1000);
    }
  }
}

// 启动循环
startLoop();

优化说明

该写法保证上一轮所有请求、页面解析逻辑全部处理完成后,才会开始计时30秒执行下一轮,不会出现请求堆积,从根源上避免了堆内存溢出的问题。

内容的提问来源于stack exchange,提问作者Sumit Ghewade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 02:30:05