Skip to content

Instantly share code, notes, and snippets.

@sintaxi sintaxi/thing.js
Last active Jul 9, 2016

Embed
What would you like to do?
A JavaScript question. What is the best way to handle this situation?
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.
@sintaxi

This comment has been minimized.

Copy link
Owner Author

commented Jun 10, 2016

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.

@edrex

This comment has been minimized.

Copy link

commented Jun 10, 2016

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
...
@neilk

This comment has been minimized.

Copy link

commented Jun 11, 2016

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
You can’t perform that action at this time.