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

Node.js中如何仅在外部API有新数据时调用以降低CPU开销?

嘿,这个问题我之前做第三方API集成的时候也碰到过,固定间隔轮询确实容易造成不必要的资源浪费,尤其是当API更新频率不稳定的时候。给你几个更高效的方案,你可以根据外部API的支持情况来选:

1. 指数退避策略(Exponential Backoff)

这是最容易落地的优化方案,核心思路是:如果检查后发现没有新数据,就逐步延长下一次检查的间隔时间;一旦发现新数据,就把间隔重置回初始值。这样既能保证在API更新频繁时及时获取数据,又能在更新稀疏时减少请求次数。

举个Node.js的简单实现:

let checkInterval = 5 * 60 * 1000; // 初始间隔5分钟
const maxInterval = 60 * 60 * 1000; // 最大间隔1小时

async function checkForUpdates() {
  try {
    const response = await fetch('https://external-api.example.com/data');
    const data = await response.json();
    
    // 这里需要你根据实际逻辑判断是否有新数据,比如对比本地存储的最新数据ID
    const hasNewData = checkIfDataIsNew(data);
    
    if (hasNewData) {
      // 处理新数据
      processNewData(data);
      // 重置间隔为初始值
      checkInterval = 5 * 60 * 1000;
    } else {
      // 没有新数据,延长间隔(不超过最大值)
      checkInterval = Math.min(checkInterval * 2, maxInterval);
    }
  } catch (error) {
    // 请求出错时,也适当延长间隔避免频繁重试
    checkInterval = Math.min(checkInterval * 2, maxInterval);
    console.error('检查API更新出错:', error);
  } finally {
    // 安排下一次检查
    setTimeout(checkForUpdates, checkInterval);
  }
}

// 启动第一次检查
checkForUpdates();

2. 利用HTTP缓存头减少无效请求

很多规范的API会返回ETag或Last-Modified响应头,你可以在后续请求中带上对应的If-None-Match或If-Modified-Since头。如果服务器判断数据没有更新,会返回304 Not Modified,此时你不需要处理响应体,直接跳过即可——这样即使保持一定的请求频率,实际的数据传输和处理开销也会大大降低。

示例(用Axios):

let lastETag = null;
let lastModified = null;

async function checkForUpdates() {
  const headers = {};
  if (lastETag) headers['If-None-Match'] = lastETag;
  if (lastModified) headers['If-Modified-Since'] = lastModified;

  try {
    const response = await axios.get('https://external-api.example.com/data', { headers });
    
    if (response.status === 304) {
      // 数据未更新,直接结束
      console.log('数据未更新');
    } else {
      // 更新缓存头
      lastETag = response.headers.etag;
      lastModified = response.headers['last-modified'];
      // 处理新数据
      processNewData(response.data);
    }
  } catch (error) {
    console.error('请求出错:', error);
  } finally {
    // 这里可以结合指数退避,或者保持一个合理的固定间隔(比如10分钟)
    setTimeout(checkForUpdates, 10 * 60 * 1000);
  }
}

3. 长轮询(Long Polling)

如果外部API支持长轮询,这是比定时轮询更高效的方式。你的服务发起请求后,服务器不会立即返回响应,而是会hold住连接,直到有新数据产生或者达到超时时间。这样你能几乎实时获取到新数据,同时避免了频繁的空请求。

实现思路大致是:

  • 你的服务向API发起长轮询请求(通常需要在请求参数里指定超时时间)
  • 服务器如果有新数据,立即返回;如果没有,就保持连接直到超时
  • 请求超时或收到新数据后,立即发起下一次长轮询

不过这个方案依赖外部API是否支持长轮询机制,你需要先查看API文档确认。

4. Webhooks(最优方案,如果API支持的话)

如果外部API提供Webhook功能,这绝对是最优解——你不需要主动去轮询,而是让API在有新数据时主动向你的服务发送通知。你只需要在API平台上配置一个接收端点(比如你的服务的/webhook接口),当API有更新时,会自动POST数据到这个端点。

这种方式完全消除了轮询的开销,而且能实时获取新数据。不过前提是外部API支持Webhook,并且你能暴露一个公网可访问的端点来接收通知。


总结一下优先级:如果API支持Webhooks,优先用;其次看是否支持长轮询;如果都不支持,就用指数退避+HTTP缓存头的组合,既能减少请求次数,又能降低无效请求的开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:33:52