Last active
July 9, 2016 22:00
-
-
Save sintaxi/5f7be7099a3d26f544522398f370cb3f to your computer and use it in GitHub Desktop.
A JavaScript question. What is the best way to handle this situation?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var expensiveThing = function(callback){ | |
setTimeout(function(){ | |
callback(null, { name: "Thurston Moore" }) | |
}, 5000) | |
} | |
var fetchAndLogExpensiveThing = function(){ | |
expensiveThing(function(err, data){ | |
console.log(err, data) | |
}) | |
} | |
// We need to do something expensive. So we do. | |
fetchAndLogExpensiveThing() | |
// We need to do the same thing several more times. | |
// How do we make the following requests use the result | |
// of the first expensive thing that we called and are | |
// waiting for? | |
setTimeout(fetchAndLogExpensiveThing, 1000) | |
setTimeout(fetchAndLogExpensiveThing, 2000) | |
setTimeout(fetchAndLogExpensiveThing, 3000) | |
setTimeout(fetchAndLogExpensiveThing, 4000) | |
// To be clear the last call should use the result of the | |
// first fetchAndLogExpensiveThing which will respond within | |
// a second. the expensiveThing() should only happen once. |
Often you can just use the promise directly - create it once, and then resolve it as many times as needed.
var expensiveThing = function(){
return new Promise(function(resolve, reject) {
setTimeout(function(){
callback(null, { name: "Thurston Moore" })
}, 5000)
});
}
var prom
var fetchAndLogExpensiveThing = function(){
if (!prom) {
prom = expensiveThing();
}
prom.then(function(err, data){
console.log(err, data)
})
}
// the rest is the same
...
Followup from Twitter discussion: this seems to work. Although, it feels a bit like we are reimplementing what a web browser does... perhaps we'd also want to evict from cache if the resource had changed.
var memoize = require('memoizee'),
rp = require('request-promise');
var getLocationPromise = memoize(function(location) {
console.log("getting a new network resource:", location);
return rp(location);
});
var printLocation = function(location) {
console.log("need to print contents:", location);
getLocationPromise(location).then(function(contents) {
console.log(contents);
});
}
var location = 'http://neilk.net/robots.txt';
setTimeout(function() { printLocation(location) }, 1000);
setTimeout(function() { printLocation(location) }, 1000);
setTimeout(function() { printLocation(location) }, 1000);
setTimeout(function() { printLocation(location) }, 1000);
setTimeout(function() { printLocation(location) }, 1000);
And if we run it:
$ node lpc.js
need to print contents: http://neilk.net/robots.txt
getting a new network resource: http://neilk.net/robots.txt
need to print contents: http://neilk.net/robots.txt
need to print contents: http://neilk.net/robots.txt
need to print contents: http://neilk.net/robots.txt
need to print contents: http://neilk.net/robots.txt
User-agent: *
Disallow:
Sitemap: http://neilk.net/sitemap.xml
User-agent: *
Disallow:
Sitemap: http://neilk.net/sitemap.xml
User-agent: *
Disallow:
Sitemap: http://neilk.net/sitemap.xml
User-agent: *
Disallow:
Sitemap: http://neilk.net/sitemap.xml
User-agent: *
Disallow:
Sitemap: http://neilk.net/sitemap.xml
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To be clear, This is a performance optimization.
I could of course cache the result of the expensive thing and use that once it comes back however Im looking to solve the specific use case of many calls to a cold cache all at once. Ideally the seconds request just waits for the response of the first. Thats the idea anyway.