使Meteor.methods同步和asynchronous

有时我需要Meteor.call来writeMeLater排队并同步执行(阻止来自同一个客户端的writeMeLater其他调用)。

其他时候writeMeLater的调用应尽快执行,而不排队等待当前排队的所有调用。

下面是我尝试使用this.unblock()如果一个async参数为true。 案例1和2工作正常。 但在案例3中,使用async=true调用在async=true调用后面排队! 我们如何使用async=true来调用跳过队列? 这与来自第二客户端的呼叫在来自第一客户端的呼叫之后没有排队是类似的,

所有的Meteor.call()都是由客户端创build的

情况1(正确同步):

 Meteor.call('writeMeLater', 's', false) Meteor.call('writeMeLater', 's', false) Meteor.call('writeMeLater', 's', false) 

情况2(正确asynchronous):

 Meteor.call('writeMeLater', 'a', true) Meteor.call('writeMeLater', 'a', true) Meteor.call('writeMeLater', 'a', true) 

情况3(不是所需的行为)

 Meteor.call('writeMeLater', 's', false) Meteor.call('writeMeLater', 's', false) Meteor.call('writeMeLater', 's', false) Meteor.call('writeMeLater', 'a', true) Meteor.call('writeMeLater', 'a', true) Meteor.call('writeMeLater', 'a', true) 

服务器/ main.js

 writeMeLater = function(data, callback) { console.log('writeMeLater: ', data) // simulate taking 3 second to complete Meteor.setTimeout(function() { Logs.insert({data: data, timestamp: new Date().getTime()}) console.log('Log.insert: ', data) callback(null, 'done') }, 3 * 1000) } writeMeLaterSync = Meteor._wrapAsync(writeMeLater) Meteor.methods({ writeMeLater: function(data, async) { if(async) this.unblock() writeMeLaterSync(data) } }) 

我的第一个想法是,为什么不实际创build一个队列? 而不是依靠JavaScript事件循环作为你的队列。 然后将文档插入到该队列中,如:

 WritesQueue = new Meteor.Collection("WritesQueue"); WritesQueue.insert({data: 'a', prioritize: true, inserted: new Date()}); 

也许每当你插入一个高优先级的写操作时,都会触发Meteor.call("write")处理队列,优先(非asynchronous)

 Meteor.methods({ write: function () { WritesQueue.find({prioritize: true}, {sort: {inserted: 1}}) .forEach(function (doc) { console.log(doc.data); WritesQueue.remove(doc._id); }); WritesQueue.find({prioritize: false}, {sort: {inserted: 1}}) .forEach(function (doc) { console.log(doc.data); WritesQueue.remove(doc._id); }); } }); 

或者,如果您希望在每次插入高优先级或低优先级写入时都处理队列,则可以调用write方法,也可以将insert内部write方法本身。 这解决了跳转到头的问题,尽pipe写入仍然是同步处理每个客户端。

至于试图为单个客户端实现并行处理,@imslavko(在上述问题的注释中)是正确的,因为实现这一目的的一种方式是让客户端build立多个DDP连接。 有一个相对简单的,虽然hacky和非meteor的方法来做到这一点:

安装Iron Router并在你的服务器代码中定义一个服务器端路由:

 Router.map(function () { this.route('writeMeLater', { where: 'server', action: function () { Meteor.call('writeMeLater', this.request.query.data, this.request.query.async); } }); }); 

上面的this.request.query是一个带有请求提交的键值对的对象。 例如:

 HTTP.post("http://yoursite.com/writeMeLater", {params: {data: 'a', async: true}}); 

据服务器知道,这个请求来自一个新的客户端,所以它将被处理在一个新的光纤(即线程)。 如果writeMeLater方法知道不等待,它的许多实例可以同时开始运行。 现在这个问题就变成了保持请求的顺序,如果服务器上的执行顺序和客户端的执行顺序一样重要,因为HTTP POST请求可能不一定按照它们的顺序到达服务器发送。 但也有不同的处理方法(分批发送,或者包括一个计数器,如果服务器检测到一个无序的请求,就等待几秒钟)。