0

THE PROMPT: We have a search that connects to an JSON API url. The search query is inside the url, and the API generates a new JSON file for every search term. We also cannot rely on the browser to cache for us, and we can't use PHP or server side caching; we need to use HTML5 LocalStorage (and we don't care that IE7 can't use it)

We need to cache every new JSON file for every new search. We want to cut down on requests per minute, so we want to use a cached version of the JSON file for repeated search terms.

WHERE I'M STUCK: What has made this difficult is caching a JSON file for each new/different search term. I have been able to cache the first search, but then all subsequent searches use the same cached JSON.

We need help rewriting this so each time a new search is made, it checks to see if the term was searched for previously and if so, grabs the corresponding JSON file. Then of course if the search term is new then cache a new JSON file for that specific search term.

WHAT I'VE TRIED: In my research I've seen a lot of very complicated solutions and I can't seem to get my head completely around all of it, some of these solutions almost worked, I think I just need a better explanation for this specific case.

I think this is the answer but I don't know how to apply it to my situation: jQuery deferred ajax cache

This is crazy and it almost works, it writes into the console when it recognizes that I've searched the same thing again, and it does stop a new request, but unfortunately the cached JSON isn't there, it returns no results. Caching a jquery ajax response in javascript/browser

WHAT I HAVE SO FAR:

MY PSUEDO CODE:

var searchTerm = WHATEVER IS TYPED INTO THE SEARCHBOX

// The JSON file
var url = 'https://api.example.com/fake/json/path/{'+searchTerm+'}';

// Local Storage Caching Promise
var cachedData = localStorage.getItem("cachedData"),
          def = $.Deferred();

if (!cachedData) {
    def = $.getJSON(url, function(data) {
        cachedData = data;
        localStorage.setItem("cachedData", JSON.stringify(cachedData));
    });
}
else{
    cachedData = JSON.parse(cachedData);
    def.resolve();
}

def.done(function() {
    var resultHTML = '';
    for(var i = 0; i < Object.keys(cachedData.things).length; i++){
      $.each(cachedData, function(index, node){
        resultHTML += '<li>'
        resultHTML  += '<h1>' + node[i].name + '</h1>';
        resultHTML += '</li>';
      });
    }
    $('div#results').html(resultHTML);

});

EXAMPLE JSON:

{
  "things": [
    {
      "type": "thing",
      "username": "randoguy",
      "name": "name001",
    },
       {
      "type": "thing2",
      "username": "randoguy2",
      "name": "name002",
    },
    ...
Community
  • 1
  • 1
LookingLA
  • 456
  • 1
  • 7
  • 11
  • 2
    You have a bunch of asynchronous code, but you're treating it as synchronous. First, instead of `def.resolve()`, use `def.resolve(cachedData)`. Then, instead of `def.done(function() {`, use `def.done(function(data) {`, and use `data` inside that callback. This way, the `done` callback will be called at the right time and with the correct data (whether it's from `localStorage` or the `$.getJSON` call) – Ian Jul 13 '14 at 17:08
  • 2
    Also, you won't be able to store simply `cachedData`, because you need to provide cached results for any `searchTerm`. So you can either make many `localStorage` items (like `searchTerm + "cachedData"), or make a big object that has a lookup per `searchTerm` – Ian Jul 13 '14 at 17:10
  • Wow thanks for the quick reply @Ian, I would like to create many `localStorage` items using `searchTerm + "cachedData"`, do you think you could elaborate on where that code goes? – LookingLA Jul 13 '14 at 17:20
  • Since you can't store objects in localstorage (only strings), I would just do what Ian said and use the searchTerm for the key in the local storage. localstorage.getItem(searchTerm) and localstorage.setItem(searchTerm, ...) You will also want to make sure you are "JSON.parse"ing your cachedData. – Zack Argyle Jul 13 '14 at 17:21
  • 2
    @LookingLA So, any time you call `localStorage.getItem` or `localStorage.setItem`, the first parameter should always be something like `.getItem(searchTerm + "-cachedData")`. That way, every search term has a unique result in `localStorage`. Same goes for saving - `.setItem(searchTerm + "-cachedData")`. I added `"-cachedData"` simply to make sure the search terms don't interfere with anything else your site uses `localStorage` for where keys may overlap – Ian Jul 13 '14 at 17:26
  • 1
    @Ian you are my hero, works perfectly now! So simple! Thank you! – LookingLA Jul 13 '14 at 17:31

1 Answers1

1

Thank you @Ian for providing the hints to my answer!

var searchTerm = WHATEVER IS TYPED INTO THE SEARCHBOX;

// The JSON file
var url = 'https://api.example.com/fake/json/path/{'+searchTerm+'}';

// BABAM! Right here, SearchTerm + "-cachedData" gets unique cached data
var cachedData = localStorage.getItem(searchTerm + "-cachedData"),
          def = $.Deferred();

if (!cachedData) {
    def = $.getJSON(url, function(data) {
        cachedData = data;
// BABAM! And here is where the unique cachedData is set! SearchTerm + "-cachedData"
        localStorage.setItem(searchTerm + "-cachedData", JSON.stringify(cachedData));
    });
}
else{
    cachedData = JSON.parse(cachedData);
    def.resolve(cachedData);
}

def.done(function(data) {
    var resultHTML = '';
    for(var i = 0; i < Object.keys(data.repositories).length; i++){
      $.each(data, function(index, node){
        resultHTML += '<li>'
        resultHTML  += '<h1>' + node[i].name + '</h1>';
        resultHTML  += '<p>' + node[i].owner + '</p>';
        resultHTML += '</li>';
      });
    }
    $('div#results').html(resultHTML);

});

Where would I be without StackOverflow. Thank you all!

LookingLA
  • 456
  • 1
  • 7
  • 11