设置蓝鸟承诺分辨率.js最小延迟
Set minimum delay on bluebird.js promise resolution
我想保证蓝鸟.js承诺的分辨率延迟最小。
举个例子,假设我正在发出一个包裹在承诺中的请求。我想要的行为是,如果请求花费的时间少于 5 秒,我想人为地将承诺解析的延迟增加到 5 秒。如果请求花费超过 5 秒的时间,我不希望添加人为延迟 - 因此这比为每个请求添加静态延迟要复杂一些。所有这些都应该对承诺的消费者完全隐藏 - 他们应该只看到承诺在 5 秒或更长时间内得到解决。
为了演示,我有一个简单的模拟实现示例,它将模拟请求延迟硬编码为 3 秒。
我的第一次尝试是这样的 - 使用 setTimeout 来确保在 5 秒过去之前不会调用解析回调。
在这里摆弄
function getTimestamp() {
return new Date().getTime();
}
function makeCallWith3SecondLatency(cb) {
console.log('mocking a call with 3 second latency...');
var mockResult = 'the result';
setTimeout(function() { cb(mockResult); }, 3000);
}
function doSomethingAsync(minDelay) {
return new Promise(function(resolve) {
var calledAt = getTimestamp();
makeCallWith3SecondLatency(function(arg) {
var actualDelay = getTimestamp() - calledAt;
if(actualDelay < minDelay) {
var artificialDelay = minDelay - actualDelay;
console.log('artificially delay another ' + artificialDelay + ' millis');
setTimeout(function() { resolve(arg); }, artificialDelay);
} else {
resolve(arg);
}
});
});
}
function printResult(result) {
console.log('result: ' + result)
}
var minDelay = 5000;
doSomethingAsync(minDelay).then(printResult);
很多样板。
然后我通过这个答案发现,我可以使用 Promise.join 函数来加入 promise 包装请求,并用至少 5 秒延迟的 Promise.delay 来实现同样的事情:
在这里摆弄
function makeCallWith3SecondLatency(cb) {
console.log('mocking a call with 3 second latency...');
var mockResult = 'the result';
setTimeout(function() { cb(mockResult); }, 3000);
}
function doSomethingAsync(minDelay) {
return Promise.join(
new Promise(function(resolve) { makeCallWith3SecondLatency(resolve); }),
Promise.delay(minDelay).then(function() { console.log('artificially delaying 5 seconds with Promise.delay') }),
function(result) { return result; });
}
function printResult(result) {
console.log('result: ' + result)
}
var minDelay = 5000;
doSomethingAsync(minDelay).then(printResult);
这更干净,但仍然比我想要的更样板 - 我已经挖掘了蓝鸟 api 参考,找不到直接执行此操作的函数。
我的问题很简单 - 有人能提出一种比第二个例子更干净、更声明性的方式来实现蓝鸟的这种行为吗?
对于API 确实提供此功能的其他承诺库的任何建议也将不胜感激。
您需要做的就是Promise.delay(value).return(promise)
:
您可以将其包装在实用程序函数中:
function stallPromise(promise, delay) {
return Promise.delay(delay).return(promise);
}
function doSomethingAsync(minDelay) {
var p = new Promise(makeCallWith3SecondLatency);
return stallPromise(p, minDelay);
}
var minDelay = 5000;
doSomethingAsync(minDelay).then(printResult);
http://jsfiddle.net/s572rg7y/1/
请注意,关于这一点的一件事是,如果承诺拒绝,延迟的承诺在五秒钟过去之前不会拒绝。这可能是期望的行为(正如 Gruenbaum 在评论中指出@Benjamin),但如果您希望它立即拒绝,另外两个选项是:
Promise.join
:
function stallPromise(promise, delay) {
// if you're using underscore/lodash, you can use _.identity for this
function identity(val) { return val; }
return Promise.join(promise, Promise.delay(delay), identity);
}
或者@Benjamin Gruenbaum的方法Promise.all
:
function minDelay(promise, delay) {
Promise.all([promise, Promise.delay(delay)]).get(0);
}
你的问题
首先,其他 3 秒调用的承诺在这里无关紧要,它不应该是承诺的一部分。虽然我很受宠若惊,但你喜欢我的回答.join
但它也不是我在这里实际使用的工具。
首先,API 调用只是一个任意的承诺返回函数。
function yourApiCall(){
// your function that returns a promise AFTER promisificatin
}
实际上,我们并不真正关心它。不妨只是:
var p = ... ; //p is a promise
现在我们要确保在解决 p 之前至少经过 3 秒。
function minDelay(p, ms){ // stealing name from JLRishe's answer
return Promise.all([p, Promise.delay(ms)]).get(0);
}
它接受任意承诺并返回至少需要 ms
毫秒才能解决的承诺。
minDelay(p, 300).then(function(el){
// el is minDelay's return value and at least 300 ms have passed
});
你也可以把它放在Bluebird的原型上(如果你正在编写一个库,一定要先得到你自己的独立副本):
Promise.prototype.minDelay = function minDelay(ms){
// note that unlike the example above this will delay
// on rejections too
return Promise.delay(ms).return(this);
}
这将允许您以声明方式执行:
p.minDelay(300).then(function(res){
// access result
});
一个更普遍的问题
通常,当人们询问这个问题时,他们真正关心的是使函数最多每隔几毫秒返回一次结果,或者使函数充当调用频率的监视器。这是为了限制对 Web 服务进行的调用次数。这应该限制在返回 promise 的函数级别。例如:
var queue = Promise.resolve();
function throttle(fn, ms){
var res = queue.then(function(){ // wait for queue
return fn(); // call the function
});
queue = Promise.delay(ms).return(queue); // make the queue wait
return res; // return the result
}
这将允许您执行以下操作:
function myApiCall(){
// returns a promise
}
var api = throttle(myApiCall, 300); // make call at most every 300 ms;
api(); // calls will be sequenced and queued
api(); // calls will be made at most every 300 ms
api(); // just be sure to call this directly, return this to consumers
下面是一个最小延迟承诺的代码示例:
const sleep = async ms => new Promise(resolve => setTimeout(resolve, ms));
const pMinDelay = async (promise, ms) => {
const [result] = await Promise.all([promise, sleep(ms)]);
return result;
};
export default pMinDelay;
将pMinDelay
函数导入您想要的位置,延迟承诺。
我希望这对;)有所帮助
库 spex 是专门为处理使用 promise 时的数据限制和负载平衡等问题而编写的。
在您的情况下,我们可以使用以下示例:
var spex = require('spex')(Promise);
function source(index, data, delay) {
var start = Date.now();
return new Promise(function (resolve) {
// request your data here;
var end = Date.now();
if (end - start < 5000) {
setTimeout(function () {
resolve();
}, 5000 - end + start);
} else {
resolve();
}
});
}
function dest(index, data, delay) {
// you can do additional load balancing here,
// while processing the data;
}
spex.sequence(source, dest)
.then(function (data) {
console.log("DATA:", data);
});
但这只是表面,因为该库允许您实现更灵活、更高级(如果需要)的策略来处理 promise 请求。
对于您的情况,可能会有趣的是传递到源函数和目标函数中的参数delay
,因此可以在需要时双向处理负载平衡。
此外,您可以使用具有相同负载平衡策略的方法页,但在页中处理请求。
- 为JS函数添加延迟
- Angular.js延迟控制器初始化
- JS在选择下拉菜单打开时创建延迟
- 节点.js:长延迟
- 如何在 JS 中调用 2 次或更多次时延迟函数执行
- 初始化Vue.js时延迟
- 在Raphael JS中,不透明度:0和开始动画到不透明度:1之间的延迟
- 延迟后JS setTimeout获取事件
- 在featherlight.js中延迟加载iFrame
- js工具提示,带有延迟的mouseout,没有jQuery
- 如何包含多个JS文件-延迟加载javascript
- 在JS文件中设置延迟以调用JS文件
- Recorder.js计算并偏移记录的延迟
- Dropzone.js延迟发布到服务器,但允许开始上传
- 如何使用js-setTimeout延迟此文本的淡入
- 延迟加载js-how
- 延迟js加载的最佳方式
- Fullpage.js.添加滚动延迟
- 延迟js函数的执行
- 如何在_的每次迭代中添加延迟?js中的每个循环