使用 Bluebird promises 创建节流函数
Creating throttling function with Bluebird promises
我正在尝试创建节流功能。我看过一些 SO 帖子并复制了一些代码,但我无法让它延迟。
基本上我在一个class中有很多方法需要调用亚马逊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;
};
我想在创建一个实际可行的解决方案后回来。把我搞砸的诀窍是你需要将未调用的函数传递给队列。我知道这不是 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(){});
我正在尝试创建节流功能。我看过一些 SO 帖子并复制了一些代码,但我无法让它延迟。
基本上我在一个class中有很多方法需要调用亚马逊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;
};
我想在创建一个实际可行的解决方案后回来。把我搞砸的诀窍是你需要将未调用的函数传递给队列。我知道这不是 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(){});