使用Bluebird承诺创建限制功能

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Bluebird承诺创建限制功能相关的知识,希望对你有一定的参考价值。

我试图创建一个限制功能。我查看了一些SO帖子并复制了一些代码,但我无法让它延迟。

基本上我在类中有许多需要调用Amazon API的方法。他们都使用了一个共同的功能 - doCall我实现如下:

Amazon.prototype.doCall = function(func) {
  var self = this;

  var queue = P.resolve();

  function throttle(fn) {
    var res = queue.then(function() { // wait for queue
      return fn(); // call the function
    });

    queue = P.delay(61000).return(queue); // make the queue wait for 61 seconds
    return res; // return the result
  }


  // Create instance of MWS client
  if (!this.client) {
    this.client = new mws.Client(key, secret, merchant, {});
  }

  var call = function() {

    // The library uses a weird signature so I am wrapping it thus
    return new P(function(resolve, reject) {

      // The original MWS library call
      self.client.invoke(func, function(r, e) {
        // ... stuff
        resolve(r);
      });
    });

  };
  return throttle(call);
};

基本上我获取订单列表和订单,需要延迟每次通话60+秒。现在,这一切都没有任何延迟。建议?

我基本上是这样使用它(做作但应该给出这个想法)

self.doCall(ListOrders).then(function(res) { 
  // parse results
  self.doCall(ListMoreOrdersByPage).then(function(res) {
     // Now I might go through each and fetch details
     var ids = [...] // Parse result for ids
     return P.map(ids, function(id) {
       return doCall(GetOrderById);
     });  
     ....
答案

你的问题是

Amazon.prototype.doCall = function(func) {
    var queue = P.resolve();
    …

表示您在每次调用该方法时重新创建一个新的queue。不太有帮助。相反,您可能希望每个Amazon有一个队列,所以将初始化放在构造函数中。

我还简化了你的代码:

function Amazon(…) {
  …
  this.queue = P.resolve();
}

Amazon.prototype.doCall = function(func) {
  if (!this.client) {
    // Create instance of MWS client
    this.client = new mws.Client(key, secret, merchant, {});
  }

  var self = this;
  var res = this.queue.then(function() {
    // The library uses a weird signature so I am wrapping it thus
    return new P(function(resolve, reject) {
      self.client.invoke(func, function(r, e) {
        // ... stuff
        resolve(r);
      });
    });
  });

  this.queue = this.queue.delay(610000); // make the queue wait for 61s
  // if you want to make it wait *between* calls, use
  // this.queue = res.catch(function(){}).delay(610000);
  return res;
};
另一答案

在我创建了一个实际的,有效的解决方案后,我想回来。让我搞砸的伎俩就是你需要将未被激活的函数传递给queuer。我知道这不是OP所要求的,但我希望这可以帮助其他任何寻求可扩展解决方案的人。

你可以在这里看到它:http://jsbin.com/seqeqecate/5/

function asyncFunction(){
  var deferred = Promise.defer();

  setTimeout(function(){
    console.log('ping');
    deferred.resolve();  
  },3000);

  return deferred.promise;
}

function AsyncQueuer(){
  var queue = [],
      running = false;

  function runQueue(){
    var first = queue.shift();

    running = true;

    if (first) {
      first.promisable.apply(first.context).then(function() {
        first.deferral.resolve();
        runQueue();
      }, 
      function() {
        first.deferral.reject();
        runQueue();
      });
    } else {
      running = false;
    }
  }

  return {
    add: function(promisable, context) {
      var deferred = Promise.defer();

      queue.push({
        promisable: promisable,
        deferral: deferred,
        context: context || window
      });

      if (!running) {
        runQueue();
      }

      return deferred;
    }
  };
}

var asyncQueuer = new AsyncQueuer();

asyncQueuer.add(asyncFunction);
asyncQueuer.add(asyncFunction);
asyncQueuer.add(asyncFunction).then(function(){}).fail(function(){});

以上是关于使用Bluebird承诺创建限制功能的主要内容,如果未能解决你的问题,请参考以下文章

使用 Bluebird 手动承诺 pg.connect

在Bluebird中刷新所有已解决的承诺

Redux Thunk, Sequelize (Bluebird) - 向动作创建者“链”返回承诺

Bluebird — 在处理程序中创建了一个承诺,但没有从它返回

像在 Q 中定义空的 Bluebird 承诺

无法得到我在 nodejs / mongoose / bluebird 中返回的承诺