使用Meteor的服务器端setInterval/clearInterval

dot*_*bat 5 javascript setinterval mongodb node.js meteor

我正在创建一个Meteor应用程序,里面有一些简单的计时器.按下定时器上的开始或停止按钮,每个调用一个方法来设置或清除间隔定时器等.当我setInterval,我将结果对象存储在当前计时器文档中,以便以后当我想清除间隔计时器时很容易找到.这是我遇到问题的地方.

运行Meteor.setInterval()服务器端时,它返回一个对象.根据node.js文档,这是正常的.如果我在创建后记录结果对象,则返回以下内容:

{ _idleTimeout: 5000,
  _idlePrev: 
   { _idleNext: [Circular],
     _idlePrev: 
      { _idleTimeout: 5000,
        _idlePrev: [Object],
        _idleNext: [Circular],
        _idleStart: 1393271941639,
        _onTimeout: [Function],
        _repeat: false },
     msecs: 5000,
     ontimeout: [Function: listOnTimeout] },
  _idleNext: 
   { _idleTimeout: 5000,
     _idlePrev: [Circular],
     _idleNext: 
      { _idleTimeout: 5000,
        _idlePrev: [Circular],
        _idleNext: [Object],
        _idleStart: 1393271941639,
        _onTimeout: [Function],
        _repeat: false },
     _idleStart: 1393271941639,
     _onTimeout: [Function],
     _repeat: false },
  _idleStart: 1393271943127,
  _onTimeout: [Function: wrapper],
  _repeat: true }
Run Code Online (Sandbox Code Playgroud)

如果我在从文档中检索对象后记录该对象,我会得到:

{ _idleTimeout: 5000,
  _idlePrev: null,
  _idleNext: null,
  _idleStart: 1393271968144,
  _repeat: true }
Run Code Online (Sandbox Code Playgroud)

因此,使用clearInterval此功能不起作用.这是我的服务器端代码:

Meteor.methods({

    play: function(entry){ //entry is the document
         var currentPlayTimer = entry; //Global variable for the interval timer
         Entries.update({_id: currentPlayTimer._id},{$set:{playing:true}}); //This is mostly to set the status of the play button for the client
         var IntervalId = Meteor.setInterval(function(){Entries.update({_id: currentPlayTimer._id},{$inc:{time:1},$set:{intervalId: IntervalId}});},5000); //Increment by 1 every 5 seconds, put the object from the interval timer into the current document
         console.log(IntervalId);
    },

    stop: function(entry){ //entry is the document
         var currentPlayTimer = entry;
         IntervalId = currentPlayTimer.intervalId;
         console.log(IntervalId);
         Meteor.clearInterval(IntervalId);
         Entries.update({_id: currentPlayTimer._id},{$set:{playing:false, intervalId: null}});

    }
});
Run Code Online (Sandbox Code Playgroud)

另外,你会注意到在play方法中,我设置intervalIdsetInterval函数内部.我绝望地尝试了这个,它起作用了.出于某种原因,如果我在创建间隔计时器后立即尝试更新文档Entries.update({_id: currentPlayTimer._id},{$set:{intervalId: IntervalId}}),则会失败.

所有这些都很适合作为客户端代码,但我需要在服务器端完成.我希望计时器能够以正确的速度继续运行,无论您是在5台设备上打开页面还是没有打开页面.

谢谢你的帮助!这个项目是我第一次使用Meteor或Node上的任何东西,到目前为止我真的非常喜欢它.

ric*_*ilv 7

这基本上归结为两个问题:首先,客户端(至少在Chrome中)和Node 中的实现setIntervalclearInterval不同,其次,您无法在BSON中序列化功能,这意味着您的所有方法,以及当您尝试将其作为文档插入服务器时,将从对象中删除包含方法的属性.这就是为什么您随后检索的对象更简单/更小,以及为什么您无法将其传递给它clearInterval,因为它缺少大部分所需信息.

如果你记录setInterval客户端的返回值,你会发现它只是一个整数,当然可以序列化,所以你得到的东西与你输入的MongoDB完全相同,并且clearInterval工作正常.我不是专家,在对所有的客户端实现set...clearInterval,但坦率地说一个四位数的整数似乎并不特别强大的用于此目的,但它确实有您已经确定了一些优势.

总而言之,我不认为你能够按照你在服务器上尝试的方式进行操作,除非其他人能够想到一种智能的方法来序列化interval所需的对象部分一旦检索到它就清除它并重建一个合适的对象,但是这需要比我拥有的Node更多的知识.否则,我认为你有两个选择:

  • 只需将您的间隔存储在某种类型的vanilla javascript对象的内存中.
  • 使用备用对象进行计时,以便存储可序列化的标识符.我meteor-cron过去曾经使用过该软件包,虽然很简单,但是可能值得一看,看看是否可以使用该软件包或其衍生产品.

  • 谢谢!那讲得通.这是我做的,对于其他任何有这个问题的人:创建一个数组来保存`setInterval`对象`var intervalArray = [];`将对象(`IntervalId`)推入数组,存储位置.这只是一个数字,所以我可以将它存储在MongoDB文档中.`intervalArrayPosition = intervalArray.push(IntervalId) - 1;`稍后,读回位置并清除如下:`Meteor.clearInterval(intervalArray [intervalArrayPosition]);` (2认同)