【问题标题】:Set and Clear Timeout on Node Server from Client从客户端设置和清除节点服务器超时
【发布时间】:2013-01-05 21:53:35
【问题描述】:

我正在尝试允许用户从客户端设置警报并将其传递给服务器。然后服务器有一个 setTimeout 倒计时,当时间用完时,执行函数。

这第一部分工作正常,但是,如果客户端决定取消该特定警报,我需要能够清除相同的超时。

注意:我一直在使用 Redis 存储各种数据,因此可用。

var client = redis.createClient();
io.set("store", new sio.RedisStore);

io.sockets.on('connection', function (socket) {

socket.on('alarm:config', function(list, date, time, bool) {

  if (bool) {

    var now = new Date().getTime();

    var year = date[0],
        month = date[1] - 1,
        day = date[2];

    var hour = time[0],
        minutes = time[1];

    var alarm = new Date(year, month, day, hour, minutes);

    var countdown = alarm - now;

    var myAlarm = setTimeout(function() {

      // do stuff...

    }, ( countdown ) );

  } else {

    clearTimeout(myAlarm);

  }

});
});

我想到的方法是使用布尔值来确定用户是在设置还是取消该特定警报。 我意识到设置一个局部变量“myAlarm”是行不通的,我只是把它放在那里传达这个想法。

我正在尝试找出一种方法来存储对该确切超时的引用,以便下次使用 false 布尔值触发“alarm:config”套接字事件时,它可以取消之前设置的超时。

这可能是另一个问题,但是像 Google 日历这样的应用程序如何存储日期和时间,然后准确地知道何时触发它以及提供取消它的能力?这基本上是相同的想法。

更新:我使用以下解决方案使其工作。我愿意接受更优雅的解决方案。

socket.on('alarm:config', function(list, date, time, bool) {

  var alarmName = "timer:" + list;

  if (bool) {

    client.hset(alarmName, "status", true);

    var now = new Date().getTime();

    var year = date[0],
        month = date[1] - 1,
        day = date[2];

    var hour = time[0],
        minutes = time[1];

    var alarm = new Date(year, month, day, hour, minutes);

    var countdown = alarm - now;

    setTimeout(function() {

      client.hget(alarmName, "status", function(err, bool) {

        if(bool == 'true') {

          // do stuff...

        } else {

          console.log("This alarm has been canceled.");

        }

      });

    }, ( countdown ) );

  } else {

    console.log('canceling alarm');
    client.hset(alarmName, "status", false);

  }
});

【问题讨论】:

  • 如何让客户端处理超时,服务器只管理警报时间戳的存储?
  • 这值得深思。我一定会记住这一点。但是,根据要求,我认为这行不通。超时功能将启动一个会影响其他用户的事件。如果发起用户关闭手机或浏览器,该操作仍应运行。
  • setTimeout() 的返回值是“对确切超时的引用”。你为什么不把它还给客户呢?
  • @Tomalak - 当计时器关闭时,它实际上会通知其他用户以及源。这可能是一种有趣的方法。您是否建议我将超时本身发送给所有不同的客户端,以便他们参考它。创建者是否应该取消该超时,告诉所有其他客户端清除该超时?这可能会很好。
  • @Andrew 是的,完全正确。据我了解,实际上只有一台机器运行超时,以及“知道”它的任意数量的机器。 setTimeout() 返回的超时 ID 将是传递的自然候选者。

标签: javascript node.js redis socket.io


【解决方案1】:

根据您要构建的应用程序的大小,有多种选择。

处理队列

您可以重组应用程序以使用作业队列,而不是简单地设置计时器。这样做的好处是您可以在将来将其拆分为多个进程,但它确实会使处理变得有点复杂。

Kue 这样的库仅使用 Redis,并允许您在将来执行延迟放置以设置事件。

从 Kue 自述文件出发:

var kue = require('kue')
  , jobs = kue.createQueue();

// Create delayed job (need to store email.id in redis as well)
var email = jobs.create('email', {
    title: 'Account renewal required',
    to: 'tj@learnboost.com',
    template: 'renewal-email'
}).delay(minute).save();

// Process job
jobs.process('email', function(job, done){
  email(job.data.to, done);
});

// Cancel job
email.remove(function(err){
  if (err) throw err;
  console.log('removed completed job #%d', job.id);
});

存储对超时的引用

这不太健壮,但可以让您非常简单地做到这一点。它使全局变量四处飘荡,如果进程崩溃则无法恢复。

基本上,您将计时器存储在全局变量中并根据作业 ID 取消它。

var myAlarms = {}

socket.on('alarm:config', function(list, date, time, bool) {
  var alarmName = "timer:" + list;

  if (bool) {

    myAlarms[alarmName] = setTimeout(function() {
      // do stuff...
    }, countdown);

  } else {
    clearTimeout(myAlarms[alarmName]);
  }
}

注意:此代码均未经过测试,可能包含错误。

【讨论】:

    猜你喜欢
    • 2018-11-04
    • 2016-06-03
    • 1970-01-01
    • 2012-11-14
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多