Meteor 如何在第一个方法调用完成之前阻止方法调用? [英] Meteor How to block a method call before the first one is finished?

查看:41
本文介绍了Meteor 如何在第一个方法调用完成之前阻止方法调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下场景:

客户端有一个按钮,点击它会在服务器端执行 Meteor.call 方法,该方法将调用 API 并获取产品,在此期间我不想禁用这个按钮 + 阻止这个再次执行的方法基本上没有什么能阻止您单击按钮 100 次,服务器将一次又一次地继续执行相同的方法.

我脑子里的几个想法:使用会话禁用按钮(问题:仍然可以使用控制台 Meteor.call 并滥用它)我还在文档中查看了 Meteor.applywait:true 似乎没有停止方法执行.老实说,我不确定如何在没有黑客的情况下处理这种事情.

客户端:

 'click .button-products': function(e){Meteor.call('getActiveProducts', function(error, results){如果(错误)返回 Alerts.add(error.reason, 'danger', {autoHide: 5000});如果(结果.成功)return Alerts.add('产品导入成功', 'success', {autoHide: 5000});})}

服务端

Meteor.methods({getActiveProducts: 函数(){var user = Meteor.user();var api = api.forUser(user);进口产品 = 功能(项目){nextPage = items.pagination.next_page;items.results.forEach(功能(产品){var sameproduct = apiProducts.findOne({listing_id: product.listing_id});如果(相同产品){返回;}var productExtend = _.extend(product, {userId: Meteor.userId()});apiProducts.insert(productExtend);});};var products = api.ProductsActive('GET', {includes: 'Images', limit: 1});进口产品(产品);while (nextPage !== null) {products = api.ProductsActive('GET', {includes: 'Images', page: nextPage, limit: 1});进口产品(产品);}返回{成功:真};}});

解决方案

来自 Meteor 文档

一个>:

<块引用>

在服务器上,来自给定客户端的方法一次运行一个.在第 N 个调用返回之前,来自客户端的第 N+1 个调用不会开始.但是,您可以通过调用 this.unblock 来更改此设置.这将允许第 N+1 次调用在新纤程中开始运行.

这意味着对该方法的后续调用实际上并不知道它们是在第一个调用仍在运行时进行的,因为第一个调用已经完成运行.但是你可以这样做:

Meteor.methods({获取活动产品:函数(){var currentUser = Meteor.users.findOne(this.userId);if (currentUser && !currentUser.gettingProducts) {Meteor.users.update(this.userId, {$set: {gettingProducts: true}});//让其他调用运行,但现在它们不会通过 if 块this.unblock();//在这里做你的实际方法Meteor.users.update(this.userId, {$set: {gettingProducts: false}});}}});

现在后续调用可能在第一个仍在运行时运行,但它们不会在 if 块内运行任何内容.理论上,如果用户发送足够多的调用,第一个调用可以在所有其他调用开始之前完成.但这至少应该显着限制用户可以发起的 etsy 调用的数量.您可以调整此技术以使其更加健壮,例如存储上次成功调用的时间并确保已过去 X 秒,或存储该方法在过去一小时内被调用的次数并限制该次数等.

I have the following scenario:

Client side has a button clicking it will execute Meteor.call method on the server-side which will call API and fetch products, During this time I wan't to disable this button + block this method from executing again basically nothing stops you from clicking the button 100x times and server will keep on executing same method again and again.

Few ideas I had in my mind: Use sessions to disable button (Problem: can still using the console Meteor.call and abuse it) I also looked at Meteor.apply in the docs with wait:true didn't seems to stop from method execution. I honestly not sure how this kind of thing is handled with no hacks.

Client-side:

  'click .button-products': function(e){
    Meteor.call('getActiveProducts', function(error, results){
      if (error)
        return Alerts.add(error.reason, 'danger', {autoHide: 5000});
      if (results.success)
        return Alerts.add('Finished Importing Products Successfully', 'success', {autoHide: 5000});
    })
  }

Server-side

Meteor.methods({
  getActiveProducts: function(){
    var user = Meteor.user();
    var api = api.forUser(user);

    importProducts = function(items){ 
      nextPage = items.pagination.next_page;
      items.results.forEach(function(product){ 
        var sameproduct = apiProducts.findOne({listing_id: product.listing_id}); 
        if (sameproduct) { 
          return;
        }
        var productExtend = _.extend(product, {userId: Meteor.userId()}); 
        apiProducts.insert(productExtend);
      });
    };

    var products = api.ProductsActive('GET', {includes: 'Images', limit: 1}); 
    importProducts(products);
    while (nextPage !== null) {
      products = api.ProductsActive('GET', {includes: 'Images', page: nextPage, limit: 1});
      importProducts(products);
   }
    return {success: true};
  }
});

解决方案

From the Meteor docs:

On the server, methods from a given client run one at a time. The N+1th invocation from a client won't start until the Nth invocation returns. However, you can change this by calling this.unblock. This will allow the N+1th invocation to start running in a new fiber.

What this means is that subsequent calls to the method won't actually know that they were made while the first call was still running, because the first call will have already finished running. But you could do something like this:

Meteor.methods({
  getActiveProducts: function() {
    var currentUser = Meteor.users.findOne(this.userId);
    if (currentUser && !currentUser.gettingProducts) {
      Meteor.users.update(this.userId, {$set: {gettingProducts: true}});

      // let the other calls run, but now they won't get past the if block
      this.unblock();

      // do your actual method stuff here

      Meteor.users.update(this.userId, {$set: {gettingProducts: false}});
    }
  }
});

Now subsequent calls may run while the first is still running, but they won't run anything inside the if block. Theoretically, if the user sends enough calls, the first call could finish before all of the others have started. But this should at least significantly limit the number of etsy calls that can be initiated by a user. You could adapt this technique to be more robust, such as storing the last time a successful call was initiated and making sure X seconds have passed, or storing the number of times the method has been called in the last hour and limiting that number, etc.

这篇关于Meteor 如何在第一个方法调用完成之前阻止方法调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆