【问题标题】:multiple setInterval timers on node server节点服务器上的多个 setInterval 计时器
【发布时间】:2019-11-14 10:56:41
【问题描述】:

我的应用是一个游戏,用户有 30 分钟的时间完成....节点后端

每次用户开始游戏时,服务器端都会触发一个 setInterval 函数....一旦倒计时 30 分钟,我就会清除Interval。

如何确保每个 setInterval 对特定用户都是唯一的,并且每次新用户开始游戏时不会覆盖 setInterval 变量? (或者每次我清除时都会清除所有 setInterval)。 似乎我可能需要为每个开始游戏的新用户创建一个唯一的“间隔”变量?

每次新用户开始游戏时都会触发以下代码

 let secondsLeft = 300000;
      let interval = setInterval(() => {
        secondsLeft -= 1000;

        if (secondsLeft === 0) {
          console.log("now exit");
          clearInterval(interval);
        }
      }, 10000);

谢谢!!

【问题讨论】:

  • 如果是我,我会记录游戏的开始时间,计算游戏的结束时间,并保存与用户ID对应的数据,而不是在服务器上使用setInterval

标签: javascript node.js setinterval


【解决方案1】:

我们将agenda 用于一个相当大的策略游戏后端,如果节点应用程序崩溃等,它可以提供持久性的好处。

我们将用户 ID 合并到作业名称中,然后安排作业以及要处理的数据在确定的时间运行,指定要执行的处理程序。

然后处理程序将运行作业并执行相关任务。

// create a unique jobname
const jobName = `${player.id}|${constants.events.game.createBuilding}`;
// define a job to run with handler
services.scheduler.define(jobName, checkCreateBuildingComplete);
// schedule it to run and pass the data 
services.scheduler.schedule(at.toISOString(), jobName, {
   id: id,
   instance: instance,
   started: when
});

工作得很好,并提供了不错的崩溃保护。也许值得考虑。

【讨论】:

    【解决方案2】:

    首先:并发间隔和定时器不是 JS 中最好的设计方法,最好使用一个全局定时器和一个存储开始、结束、用户 ID 等的对象列表并在循环中更新它们。

    无论如何。要将间隔 id 绑定到某个范围,可以使用 Promise,如下所示:

    const createTimer = (duration, userid) => new Promise(res => {
      const start = new Date().getTime();
    
      let iid;
    
      (function loop () {
        const 
          now = new Date().getTime(),
          delta = now - start
        ;
        //elapsed
        if (delta >= duration) {
          clearTimeout(iid);
          res(userid);
        //try again later
        } else {
          iid = setTimeout(loop, 100)
        }
      })();
    });
    

    这样每个计时器都将“独立运行”。我在这里使用了setTimeout,因为它不会重新排队loop,然后才能完成它必须做的一切。它也应该与 setInterval 一起使用,并且看起来像这样:

    const runTimer = (duration, userid, ontick) => new Promise(res => {
      const 
        start = new Date().getTime(),
        iid = setInterval(
          () => {
            const delta = new Date().getTime() - start;
    
            if (delta < duration) {
            //if you want to trigger something each time
            ontick(delta, userid);
    
            } else {
              clearInterval(iid);
              res(userid);
            }
    
    
          }, 500)
      ;
    
    });
    

    你甚至不需要一个promise,一个简单的函数也可以,但是你必须构建一些解决方案来在计时器到时触发一些东西。

    【讨论】:

      【解决方案3】:

      感谢@Chev 和@philipp,这些都是很好的答案。

      我还了解到一种技术,您可以将数组用于 setInterval 变量.....这将使我的代码如下所示;

       let intervals = []
       let secondsLeft = 300000;
            intervals['i'+userId] = setInterval(() => {
              secondsLeft -= 1000;
      
              if (secondsLeft === 0) {
                console.log("now exit");
                clearInterval(interval);
              }
            }, 10000);
      

      还有其他人预见到这会起作用吗?

      太平洋标准时间下午 6.56 点更新.....它有效!!

      【讨论】:

      • 如果ID合适,您可以简单地保留一个对象,或者像intervals[userID] = setInterval(..)等间隔的引用数组。这不是一个强大的解决方案,因为服务器重新启动/崩溃然后你所有的玩家都有麻烦了!
      猜你喜欢
      • 2021-05-23
      • 2019-12-12
      • 1970-01-01
      • 2012-03-24
      • 2020-09-08
      • 2020-02-25
      • 2012-08-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多