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

socket.io对接ioBroker时clearInterval无法终止定时器问题排查

解决ioBroker中setInterval定时器重复运行的问题

我在适配ioBroker的socket.io环境中,通过setInterval每秒展示最后接收时间戳的“多久之前”信息。首次运行正常,但当收到第二个更新后的时间戳时,旧定时器没有被clearInterval终止,导致新旧定时器同时运行。

需求:

  • 当onUpdate触发并收到新时间戳时,启动定时器每秒更新“多久之前”的显示
  • 后续(比如2-3分钟后)收到新值时,必须终止当前定时器,再启动新定时器,展示新时间戳对应的信息(如“几秒前”“2分钟前”等)

问题根源

  1. timerId作用域错误:原来的timerId是在getStates回调内部定义的局部变量,每次onUpdate都会创建新的timerId,导致无法访问到之前的定时器ID,无法清除旧定时器。
  2. 未主动清除旧定时器:创建新定时器前没有检查并清除已存在的定时器,导致多个定时器同时运行。
  3. 冗余的getStates调用:stromvIDts是状态对象本身的ts字段,不需要再调用getStates获取,直接使用即可。

修复方案

  1. 将timerId提升到全局作用域,确保每次onUpdate都能访问到同一个变量。
  2. 在创建新定时器前,先检查timerId是否存在,若存在则调用clearInterval清除旧定时器。
  3. 移除冗余的getStates([stromvIDts])调用,直接使用已有的时间戳。

修改后的完整代码

JavaScript代码

servConn.namespace = 'mobile.0';
servConn._useStorage = false;

var stromv = 'hm-rpc.1.MEQ123456.1.POWER';
var subscriptions = [stromv];
var states = [];
// 把timerId提升到全局作用域
var timerId = null;

servConn.init({
  name: 'mobile.0',
  connLink: 'http://IP:8082',
  socketSession: ''
}, {
  onConnChange: function(isConnected) {
    console.log(isConnected ? 'connected' : 'disconnected');
  },

  onUpdate: function(id, state) {
    setTimeout(function() {
      states[id] = state;

      let stromvID = states[stromv].val;
      let stromvIDts = states[stromv].ts;

      // 更新当前数值显示
      document.getElementById("stromvAktuell").innerHTML = stromvID + " W/h";

      // 先清除旧定时器(如果存在)
      if (timerId) {
        clearInterval(timerId);
      }

      // 启动新定时器
      timerId = setInterval(function() {
        let duration = moment(stromvIDts).fromNow();
        console.log(duration);
        document.getElementById("stromvTs").innerHTML = duration;
      }, 1000);

    }, 0);
  },

  onError: function(err) {
    window.alert(_('Cannot execute %s for %s, because of insufficient permissions', err.command, err.arg), _('Insufficient permissions'), 'alert', 600);
  }
}, false, false);

servConn._socket.emit('subscribe', subscriptions);

HTML代码(无需修改)

<!DOCTYPE html>
<html lang="de">

<head>
  <link rel="icon" href="data:,">
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
  <title>TEST</title>
  <script src="http://IP:8082/socket.io/socket.io.js"></script>
  <script src="../tmp/conn.js"></script>
  <script src="moment-with-locales.js"></script>
  <script>
    moment.locale('de')
  </script>
</head>

<body>
  <div>
    Value: <b id="stromvAktuell">unknown</b>
    <br> Last update: <b id="stromvTs">unknown</b>
    <br>
  </div>
</body>

关键说明

  • 全局timerId:确保每次onUpdate都能引用到同一个定时器ID,清除旧定时器时不会找不到目标。
  • 先清后建:每次收到新时间戳时,先终止旧定时器再创建新的,保证始终只有一个定时器在运行。
  • 简化逻辑:移除不必要的getStates调用,减少异步请求开销,提升代码效率。

内容的提问来源于stack exchange,提问作者Kai L.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 12:45:35