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

Chrome中setInterval执行超时警告及应用冻结问题求助

解决setInterval回调耗时过长引发的Violation警告与应用冻结问题

我明白你的困扰——明明不能修改核心的过滤逻辑,却要解决这个讨厌的[Violation] 'setInterval' handler took N ms警告,还得防止应用冻结。咱们先搞清楚问题出在哪,再给你几个不用改过滤逻辑就能解决的方案:

问题根源

setInterval的特性是不管前一次回调有没有执行完成,到了设定的时间就会触发新的回调。当你的过滤逻辑(尤其是getFilteredListOfTurbine里的循环和规则校验)耗时超过1000ms时,新的回调会被堆积在任务队列里,抢占主线程资源,最终触发警告甚至导致应用冻结。

可行解决方案

1. 用setTimeout替代setInterval,实现“串行间隔执行”

把固定间隔的setInterval改成递归调用的setTimeout,这样只有前一次回调完全执行完毕后,才会设置下一次的定时器,从根本上避免任务堆积。

修改你的定时器代码:

let cardIntervalId;

function updateCardData() {
  if (self.filterObject != undefined) {
    self.getFilteredListOfTurbine(self.globalFilterService.getUpdatedTurbineListWithOperatingMode(self.listOfTurbine))
      .then((response) => {
        self.cardData.turbines = response;
        self.cardData.recalculate();
        observable.next(self.cardData);
        // 前一次任务完成后,再设置下一次定时器
        cardIntervalId = setTimeout(updateCardData, 1000);
      });
  } else {
    self.cardData.turbines = self.globalFilterService.getUpdatedTurbineListWithOperatingMode(self.listOfTurbine);
    self.cardData.recalculate();
    observable.next(self.cardData);
    // 直接设置下一次定时器
    cardIntervalId = setTimeout(updateCardData, 1000);
  }
}

// 启动首次执行
cardIntervalId = setTimeout(updateCardData, 1000);

// 如果需要停止定时器,用clearTimeout(cardIntervalId)

2. 将耗时过滤逻辑移到Web Worker中

Web Worker运行在独立的后台线程,不会阻塞主线程。你不需要修改过滤逻辑的代码,只需要把getFilteredListOfTurbine的逻辑迁移到Worker里,主线程负责传递数据和接收结果。

步骤1:创建一个过滤Worker文件(比如turbineFilter.worker.js)

// 把原有的getFilteredListOfTurbine逻辑复制到这里
self.onmessage = function(e) {
  const { listOfTurbine, filterObject } = e.data;
  let listOfFilteredTurbine = [];

  if (!filterObject) {
    self.postMessage(listOfTurbine);
    return;
  }

  listOfTurbine.forEach((turbine, i) => {
    if (filterObject.wf.includes(turbine.wfoid) && 
        filterObject.tu.includes(turbine.turbineserialnumber) && 
        filterObject.tt.includes(turbine.hwtype) && 
        filterObject.om.includes(turbine.turbineoperatingmode)) {
      if (filterObject.ro && filterObject.ro.length > 0) {
        let addTurbine = applyRulesOnTurbine(turbine, getRuleObject());
        if (addTurbine) {
          listOfFilteredTurbine.push(turbine);
        }
      } else {
        listOfFilteredTurbine.push(turbine);
      }
    }
    if (i === listOfTurbine.length - 1) {
      self.postMessage(listOfFilteredTurbine);
    }
  });

  // 把原有的applyRulesOnTurbine和getRuleObject方法也复制到这里
  function applyRulesOnTurbine(turbine, ruleObj) {
    // 原方法逻辑
  }

  function getRuleObject() {
    // 原方法逻辑
  }
};

步骤2:修改主线程的定时器代码,使用Worker

// 创建Worker实例
const filterWorker = new Worker('./turbineFilter.worker.js');
let cardIntervalId;

function updateCardData() {
  const turbineList = self.globalFilterService.getUpdatedTurbineListWithOperatingMode(self.listOfTurbine);
  
  if (self.filterObject != undefined) {
    // 向Worker发送数据
    filterWorker.postMessage({
      listOfTurbine: turbineList,
      filterObject: self.filterObject
    });
  } else {
    self.cardData.turbines = turbineList;
    self.cardData.recalculate();
    observable.next(self.cardData);
    cardIntervalId = setTimeout(updateCardData, 1000);
  }
}

// 监听Worker的结果返回
filterWorker.onmessage = function(e) {
  self.cardData.turbines = e.data;
  self.cardData.recalculate();
  observable.next(self.cardData);
  // 任务完成后设置下一次定时器
  cardIntervalId = setTimeout(updateCardData, 1000);
};

// 启动首次执行
cardIntervalId = setTimeout(updateCardData, 1000);

// 停止时记得销毁Worker和定时器
// filterWorker.terminate();
// clearTimeout(cardIntervalId);

3. 增加执行锁,避免并发执行过滤任务

如果不想改定时器类型,也可以加一个标志位,确保同一时间只有一个过滤任务在执行,防止任务叠加。

修改你的定时器代码:

let cardInterval;
let isFiltering = false; // 执行锁标志

cardInterval = setInterval(() => {
  if (isFiltering) return; // 如果正在过滤,跳过本次触发
  
  isFiltering = true;
  if (self.filterObject!= undefined) {
    self.getFilteredListOfTurbine(self.globalFilterService.getUpdatedTurbineListWithOperatingMode(self.listOfTurbine))
      .then((response) => {
        self.cardData.turbines = response;
        self.cardData.recalculate();
        observable.next(self.cardData);
        isFiltering = false; // 任务完成,释放锁
      });
  } else {
    self.cardData.turbines = self.globalFilterService.getUpdatedTurbineListWithOperatingMode(self.listOfTurbine);
    self.cardData.recalculate();
    observable.next(self.cardData);
    isFiltering = false; // 任务完成,释放锁
  }
}, 1000);

这个方案简单直接,但如果过滤逻辑持续耗时超过1000ms,会导致部分定时器触发被跳过,更新频率可能降低,适合对实时性要求不是极高的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:43:36