I want to guarantee a minimum delay on the resolution of a bluebird.js promise.
As an example, let's say I'm making a request wrapped in a promise. The behaviour I want is that if the request takes less than 5 seconds, I want to artificially increase the delay of the promise resolution to 5 seconds. If the request were to take more than 5 seconds, I'd want no artificial delay added - so it's a little more complicated than just adding a static delay to every request. All of this should be completely hidden from the consumer of the promise - they should just see the promise being resolved in 5 seconds, or more.
To demonstrate, I've got a simple mock implementation example which hardcodes the mocked request latency at 3 seconds.
My first try went something like this - using a setTimeout to ensure the resolve callback isn't called before 5 seconds have passed.
fiddle here
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);
A lot of boilerplate.
I then discovered through this answer that I could use the Promise.join function to join the promise wrapping the request with a Promise.delay of the minimum 5 second delay to achieve the same thing:
fiddle here
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);
This is cleaner, but still a little more boilerplate than I'd like - I've dug around the bluebird api reference and can't find a function which does this directly.
My question is simple - can anybody suggest a cleaner, more declarative way of achieving this behaviour with bluebird than the second example?
Any suggestions of other promise libraries where the api does offer this would also be appreciated.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…