嵌套在设置间隔中的超时设置中的计数器在每个回调中多次求和

如何解决嵌套在设置间隔中的超时设置中的计数器在每个回调中多次求和

我有一些代码旨在更新设置间隔块内的计数器。我的意图是每次调用设置的超时函数时都会更新一次计数器。但似乎 setTimeout 的回调在超时的整个持续时间内都处于活动状态,因此计数器在 3 秒超时时间内重复求和,导致它的结束值为 8 而不是所需的值 2。 我试图了解如何实现这一点,在超时后立即调用计数器,并且只调用一次。不幸的是,简单地把它放在函数之后似乎并不能解决这个问题。

let count = 1;
let flag = 1;
setInterval(() => {
   if (flag == 1) {
       setTimeout(()=>{
           flag = 0;
           count++;
           },3000);
    }
},500);

解决方法

那个?

let count = 1,flag  = 1,noTimCall = true
  ;
setInterval(() =>
  {
   if (flag === 1 && noTimCall)
    {
    noTimCall = false
    setTimeout(()=>
      {
      flag = 0
      count++
      noTimCall = true
      },3000)
    }
  },500)
,

让我们一步一步地检查您的代码。

  • 0 毫秒自开始。 flag1 ⇒ 创建的第一个超时。
  • 自开始以来 500 毫秒。 flag1 ⇒ ...
  • 自开始以来 3000 毫秒。 flag1 ⇒ 创建的第 7 次超时。
  • 执行第一个超时:将 flag 设置为 0,将 count 增加为 2
  • 自开始以来 3500 毫秒。 flag0 ⇒ 实际上什么都没有。
  • 已执行第二次超时:……,将 count 增加到 3
  • 自开始以来 4000 毫秒。 flag0 ⇒ ...
  • 第三次超时执行:……
  • 自开始以来 6000 毫秒。 ……
  • 已执行第 7 次超时:……,将 count 增加到 8

如您所见,将创建 7 个超时,每个超时以 count 递增 1,在 count 处以 8 结尾。

有多种方法可以在延迟后仅增加一次 count

  1. 不使用超时。我们可以手动跟踪经过了多少时间,并在达到某个阈值(此处:3 秒)后增加 count
    同步更改变量意味着它们将在间隔回调期间拥有新值,这与使用超时不同,在回调之后更改它们。
  2. 增加 count 当且仅当 flag 通过该超时回调从 1 更改为 0。更远:
    1. 始终创建超时。无论如何,它们内部的检查只负责增加 count 一次。
    2. 仅创建一次超时。这将需要一个新变量。
  3. 在间隔回调之外创建超时。但是,这意味着我们无法检查何时从我们的时间间隔内启动它,因为它是在外部立即创建的。

1。跟踪时间

为了跟踪时间,我们需要引入一个新变量,该变量在我们的间隔回调结束时随着间隔的延迟而增加。

现在我们只需要根据阈值(此处:3000 毫秒)检查经过的时间,并在满足该条件后执行特定操作。

我们可以通过允许启用/禁用 if 块来进一步扩展我们的代码。这可以使用布尔值简单地完成。

let count = 1;
let flag = 1;

let timePassed = 0; // Tracks passed time
let isStoppingEnabled = true; // Allows toggling of the stopping if-block
// Re-starting the timer requires re-setting both variables above; see last arrow expression below

setInterval(() => {
  if (flag == 1) {
    
    // Runs once 'timePassed' reaches its threshold of 3000
    // and this if-block is "enabled" (see 'isStoppingEnabled')
    if (isStoppingEnabled && timePassed >= 3000) { 
      // Will "disable" _this_ if-block;
      // disabling outer if-block using 'flag = 0;' also works
      isStoppingEnabled = false; 
      count++;
    }
  }
  
  console.log(count);
  
  timePassed += 500; // Remember to increase 'timePassed' by the interval's delay
},500);

document.querySelector('#re-stop').addEventListener('click',() => {
  isStoppingEnabled = true; // Re-enable said if-block
});
document.querySelector('#re-stop-track').addEventListener('click',() => {
  isStoppingEnabled = true; // Re-enable said if-block and...
  timePassed = 0; // re-start time tracking
});
body { /* Ignore; better styling */
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1rem 0.5rem;
}
<button id="re-stop">Re-enable stopping</button>
<label for="re-stop">
  Since 'timePassed' will most likely be already<br>
  over its threshold of 3000,'count' will be increased almost immediately. 
</label>
<button id="re-stop-track">Re-enable stopping and re-set time-tracker</button>
<label for="re-stop-track">
  Will re-set 'timePassed',effectively re-starting<br>
  the 3 second timer until 'count' is increased.
</label>

注意:警惕整数“溢出”! JavaScript 不会警告 unsafe integers 的使用!确保将时间跟踪变量保持在整数的安全范围内。

2.使用 setTimeout()

我们可以创建超时来检查它们是否应该使用一个简单的 if 语句执行。

2.1 允许多次超时

flag 设置为 1 时将运行的简单程序如下所示:

let count = 1;
let flag = 1;

setInterval(() => {
  if (flag == 1) {
    setTimeout(() => {
      if (flag == 1) {
        flag = 0;
        count++;
      }
    },3000);
  }
  
  console.log(count);
},500);

然而,这将创建超时只要创建的第一个超时没有运行,因为在那之前,if语句被执行,创建更多的超时。从技术上讲,这会正常工作,但实际上,它会产生不必要的超时,产生不必要的开销

2.2 限制超时创建

我们可以使用一个布尔值来限制一次超时的数量,因为我们只想知道一个是否已经创建。

let count = 1;
let flag = 1;

// Prefixed with "_" (underscore) because it has
// no further relevance outside of this script; should actually be private
let _isTimeoutCreated = false;

setInterval(() => {
  if (flag == 1) {
    if (!_isTimeoutCreated) { // Only create a timeout when none was created before
      _isTimeoutCreated = true; // Dis-allow creation of new timeout
      
      setTimeout(() => {
        _isTimeoutCreated = false; // Allow creation of new timeout
        flag = 0;
        count++;
      },3000);
    }
  }
  
  console.log(count);
},500);

3.在 setInterval()

之外创建超时

最简单的方法是在创建间隔后创建单个超时。
两者几乎同时创建,因为超时和间隔是异步的,允许进一步执行当前调用。

如果不是,那么脚本将卡在该行,使您的网站无响应(因为渲染和脚本执行共享同一个线程)。

它们是异步的(这里的意思是:“非阻塞”)意味着,当间隔执行时,超时的计时器仍然会倒计时,在间隔创建 3 秒后执行。

这个解决方案的问题是,如果您想在开始循环后立即开始停止过程,它只会是一个可行的解决方案。您可以从您的时间间隔内开始一个新的超时,但这会使您再次使用点 2.1 或点 2.2。

let count = 1;
let flag = 1;

setInterval(() => {
  if (flag == 1) {
    console.log(count);
  }
},500);

setTimeout(() => {
  flag = 0;
  count++;
  console.log(count);
},3000);

尾注

显然,还有其他方法可以做到这一点,比如清除间隔并创建一个新的间隔来启动/停止它。这可以包装在实用程序类中。或者可以使用现有库的计时器。或者人们可以找到一种我无法想到的方法。

最后一个重要的注意事项是始终考虑您产生的开销,尤其是在性能很重要的环境中。 但是(!)不应该仅仅因为性能原因而改变他的方式到不同的实现,如果它们不是必需的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-