0

I have a function, which retrieves data from the database and passes it to callback. For optimization purposes I want this data to be updated at most once per 60 seconds. My closure function looks like:

function delayedUpdate(fn, delay, callback) {
  var nextCall = Date.now();
  var data = false;

  (function () {
    if (nextCall <= Date.now()) {
      nextCall = Date.now() + delay;
      fn(function (err, res) {
        data = err ? false : res;
        callback(err, data);
      });
    } else {
      callback(null, data);
    }
  })();
}

I noticed that when I "construct" this function in my desired funtion, which is called very often I'm basically creating a closure in loop, so it has no chance to work properly:

function update()
{
  delayedUpdate(server.getDbData, 60000, function (err, data) {
    someDataToRender = data;
  });
}

Wrapping delayedUpdate in other function and assigning to variable doesn't work aswell. How can I accomplish my goal? I know this might be dumb question, but I'm still learning.

Selenir
  • 718
  • 1
  • 8
  • 17
  • 1
    You're calling your "delayedUpdate" function, but you're not paying any attention to the returned function. It'll return that function, your code ignores it, so nothing will ever happen. – Pointy Oct 08 '15 at 21:11
  • I've messed up. I had an IIFE instead of returning a function. Edited it. – Selenir Oct 08 '15 at 21:13
  • OK, so with the IIFE the code in that inner function will run essentially immediately, and `nextCall` will almost certainly be exactly the same or possibly very slightly less than the current date. There's really no interesting closure involved at all when it's an IIFE, because the inner function invocation is over and done with by the time the outer function returns. – Pointy Oct 08 '15 at 21:16
  • Okay, I understand. So should I return the function, assign it to variable outside the `update` function's scope and invoke it in the `update`? – Selenir Oct 08 '15 at 21:18
  • 1
    I'm not sure; I don't really understand what you're trying to achieve overall. – Pointy Oct 08 '15 at 21:19
  • I want to make a function which retrieves data from the server, stores it and passes to callback. When function is called again before delay time it should return the stored data, otherwise it should retrieve the data from the server again, and pass the updated one. – Selenir Oct 08 '15 at 21:22
  • Apart from [the problem with the context](http://stackoverflow.com/q/20279484/1048572), it sounds what you're looking for is [a debounce function](http://stackoverflow.com/q/30222791/1048572). But you're using [the wrong approach for that](http://stackoverflow.com/q/29697116/1048572). – Bergi Oct 08 '15 at 21:35

2 Answers2

1

I think what you want is something like your original code:

function delayedUpdate(fn, delay, callback) {
  var nextCall = Date.now();
  var data = false;

  return function () {
    if (nextCall <= Date.now()) {
      nextCall = Date.now() + delay;
      fn(function (err, res) {
        data = err ? false : res;
        callback(err, data);
      });
    } else {
      callback(null, data);
    }
  };
}

Then your update function would be:

var update = delayedUpdate((server.getDbData, 60000, function (err, data) {
  someDataToRender = data;
});

That is, update is the function returned from calling delayedUpdate. When you call update, it will do that timestamp check.

One thing to note: that getDbData function might not like being called without the context of that server object, whatever it is. If so, then the setup should look like:

var update = delayedUpdate((server.getDbData.bind(server), 60000, function (err, data) {
  someDataToRender = data;
});
Pointy
  • 405,095
  • 59
  • 585
  • 614
0

Your code is fine. You just need to declare the variables nextCall and data outside of the function:

var nextCall = Date.now();
var data = false;

function delayedUpdate(fn, delay, callback) {

    if (nextCall <= Date.now()) {

        nextCall = Date.now() + delay;

        fn(function (err, res) {
            data = err ? false : res;
            callback(err, data);
        });
    } else {
        callback(null, data);
    }
}
Tim
  • 5,521
  • 8
  • 36
  • 69