2

Is it possible to get the modified timestamp of a file using just JavaScript?

I use a JSON file to fill a page by javascript and I would like to show the timestamp of that JSON file.

rubo77
  • 19,527
  • 31
  • 134
  • 226
  • Related question: http://stackoverflow.com/questions/11860219/is-it-possible-to-access-the-file-creation-time-of-an-img-src-in-javascript – Casey Falk Jul 31 '14 at 14:54
  • Or perhaps better: http://stackoverflow.com/a/7612943/2456258 – Casey Falk Jul 31 '14 at 14:56
  • @casey: Those may not actually be accurate, if you form your XHR call carefully... rubo77: Is it okay if it's the creation time *as far as the server knows*? (If not, I really don't see it other than embedding the data.) – T.J. Crowder Jul 31 '14 at 14:56
  • @T.J.Crowder sure, that would be enough – rubo77 Jul 31 '14 at 15:01
  • Would like a solution that pulls the timestamp from the file itself rather than server filesystem metadata. – Tom Russell Feb 24 '23 at 07:18

1 Answers1

2

You can do it if you're retrieving the file through true ajax (that is, through XMLHttpRequest), provided you configure your server to send the Last-Modified header when sending the data.

The fundamental thing here is that when you use XMLHttpRequest, you can access the response headers. So if the server sends back Last-Modified, you can use it:

var xhr = $.ajax({
    url: "data.json",
    success: function(response) {
        display("Data is " + response.data + ", last modified: " + xhr.getResponseHeader("Last-Modified"));
    }
});

Just tried that on Chrome, Firefox, IE8, and IE11. Worked well (even when the data was coming from cache).


You've said below that you need to do this in a loop, but you keep seeing the last value of the variable. That tells me you've done something like this:

// **WRONG**
var list = /*...some list of URLs...*/;
var index;
for (index = 0; index < list.length; ++index) {
    var xhr = $.ajax({
        url: list[index],
        success: function(response) {
            display("Data is " + response.data + ", last modified: " + xhr.getResponseHeader("Last-Modified"));
        }
    });
}

The problem there is that all of the success callbacks have an enduring reference to the xhr variable, and there is only one of them. So all the callbacks see the last value assigned to xhr.

This is the classic closure problem. Here's one solution:

var list = /*...some list of URLs...*/;
list.forEach(function(url) {
    var xhr = $.ajax({
        url: url,
        success: function(response) {
            display("Data for " + url + " is " + response.data + ", last modified: " + xhr.getResponseHeader("Last-Modified"));
        }
    });
});

Since each iteration of the forEach callback gets its own xhr variable, there's no cross-talk. (You'll need to shim forEach on old browsers.)


You said below:

I already thought about a closure problem, thats why I used an array xhr[e] in my loop over e... But your example doesent help...

and linked to this code in a gist:

//loop over e....
nodename=arr[e];
node_json=path_to_node_json+nodename;
html +='<a href="'+node_json+'" target="_blank" id="host_'+nodename+'">data</a></td>'
    +'</tr>';
xhr[e] = $.ajax({
    url: node_json,
    success: function(response) {
        $('#host_'+nodename).append("last modified: " + xhr[e].getResponseHeader("Last-Modified"));
    }
});

That still has the classic error: Your success function closes over the variable e, not the value it had when the success function was created, and so by the time the success function runs, e has the last value assigned to it in the loop.

The forEach example I gave earlier fits this perfectly:

// (I assume `node_json`, `html`, and `path_to_node_json` are all declared
// here, outside the function.)
arr.forEach(function(nodename) {
    var xhr; // <=== Local variable in this specific call to the iteration
             // function, value isn't changed by subsequent iterations
    node_json=path_to_node_json+nodename;
    html +='<a href="'+node_json+'" target="_blank" id="host_'+nodename+'">data</a></td>'
        +'</tr>';
    xhr = $.ajax({
        url: node_json,
        success: function(response) {
            // Note: You haven't used it here, but just to emphasize: If
            // you used `node_json` here, it would have its value as of
            // the *end* of the loop, because it's not local to this
            // function. But `xhr` is local, and so it isn't changed on
            // subsequent iterations.
            $('#host_'+nodename).append("last modified: " + xhr.getResponseHeader("Last-Modified"));
        }
    });
});
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • This seems to work (at least on the same domain) How do I get a variable submitted from the call into the `function(response)`? If I call several of these calls in a loop I always have only the last value in the subfunction – rubo77 Jul 31 '14 at 19:18
  • I already thought about a closure problem, thats why I used an array `xhr[e]` in my loop over `e` and I get successfull cals to alll different urls. But your example doesent help, I have this problem: https://gist.github.com/rubo77/4a9077c65f8bdd5b652c I always only get the id for the last a href – rubo77 Jul 31 '14 at 19:44
  • I redefined the follof up problem here: [Submit variables into a loop of ajax calls](http://stackoverflow.com/q/25067809) – rubo77 Jul 31 '14 at 19:54
  • @rubo77: The code there still had the classic closure problem, and `forEach` fixes it. See the updated answer. But all of this is really tangential to the question you asked about finding the modified time. – T.J. Crowder Aug 01 '14 at 07:31
  • I already fixed it with arr.map() here: [Pass a variable to a function from inside an ajax call](http://stackoverflow.com/a/25068606) but thanks for your help – rubo77 Aug 01 '14 at 07:41
  • @rubo77: `map` or `forEach`, it's the same idea: Create something *else* for the handler to close over. :-) – T.J. Crowder Aug 01 '14 at 07:45