1

Below is my code and issue is with cache code is not working properly if any ajax call has callback in success.

var localCache = {
    /**
     * timeout for cache in millis
     * @type {number}
     */
    timeout: 30000,
    /** 
     * @type {{_: number, data: {}}}
     **/
    data: {},
    remove: function (url) {
        delete localCache.data[url];
    },
    exist: function (url) {
        return !!localCache.data[url] && ((new Date().getTime() - localCache.data[url]._) < localCache.timeout);
    },
    get: function (url) {
        console.log('Getting in cache for url' + url);
        return localCache.data[url].data;
    },
    set: function (url, cachedData, callback) {
        localCache.remove(url);
        localCache.data[url] = {
            _: new Date().getTime(),
            data: cachedData
        };
        if ($.isFunction(callback)) callback(cachedData);
    }
};

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
    if (options.cache) {
        var complete = originalOptions.complete || $.noop,
            url = originalOptions.url;
        //remove jQuery cache as we have our own localCache
        options.cache = false;
        options.beforeSend = function () {
            if (localCache.exist(url)) {
                complete(localCache.get(url));
                return false;
            }
            return true;
        };
        options.complete = function (data, textStatus) {
            localCache.set(url, data, complete);
        };
    }
});

function handleAjaxRequests(url, parameters, headers, method, successHandler, options, errorHandler) {

        if (typeof (method) === 'undefined') {
            method = "GET";
        }
        if (typeof (headers) === 'undefined') {
            headers = "";
        }
        if (typeof (parameters) === 'undefined') {
            parameters = "";
        }
        successHandler = typeof (successHandler) === 'undefined' ? function (data) {} : successHandler;
        errorHandler = typeof (errorHandler) === 'undefined' ? function (data) {} : errorHandler;
        return $.ajax({
            method: method.toUpperCase(),
            url: url,
//            async: false,
            data: parameters,
            headers: headers,
            success: function (data) {
                console.log('hi');
                successHandler(data, options);
                console.log('bye');
            },
            error: function (data) {
                $('.loader').hide();
                errorHandler(data);
            },
        });
    }

As per the above code after successfully run ajax successHandler(data, options);function should be the trigger but it not due to above cache handler code. I have no idea why this is not working. If I write simple something rather than callback function it is working. Same issue with datatable Ajax callbacks. I have to use above cache handler at global level in my project doesn't matter ajax request is from datatable or from any other source.

Above cache code is from here https://stackoverflow.com/a/17104536/2733203

7
  • is 'hi' printing ? Commented Sep 1, 2017 at 13:02
  • @82Tuskers It prints when the request is not cached. After request cached it not print hi. Commented Sep 1, 2017 at 13:05
  • also can you let us know how you are calling handleAjaxRequests(...) ? Also, could you enter a debug statement in your AJAX error handler too ? Commented Sep 1, 2017 at 13:14
  • this is just a function we passing parameters for that like handleAjaxRequests(url, parameters, headers, method, successHandler, options, errorHandler) this Commented Sep 1, 2017 at 13:17
  • No like have you inspected the arguments when handleAjaxRequests is called ? Commented Sep 1, 2017 at 13:20

1 Answer 1

2

As discussed in the chatroom I've made some changes in your code :

var localCache = {
  /**
   * timeout for cache in millis
   * @type {number}
   */
  timeout: 30000,
  /** 
   * @type {{_: number, data: {}}}
   **/
  data: {},
  remove: function(url) {
    delete localCache.data[url];
  },
  exist: function(url) {
    return !!localCache.data[url] && ((new Date().getTime() - localCache.data[url]._) < localCache.timeout);
  },
  get: function(url) {
    console.log('Getting in cache for url ' + url);
    return localCache.data[url].data;
  },
  set: function(url, cachedData, callback) {
    localCache.remove(url);
    localCache.data[url] = {
      _: new Date().getTime(),
      data: cachedData
    };
    console.debug('caching data for '+url, cachedData);
    if ($.isFunction(callback)) callback(cachedData);
  }
};

$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
  if (options.cache) {
    var complete = originalOptions.complete || $.noop,
      url = originalOptions.url;
    //remove jQuery cache as we have our own localCache
    options.cache = false;
    options.beforeSend = function() {
      if (localCache.exist(url)) {
        console.log('using cache, NO QUERY');
        complete(localCache.get(url));
        return false;
      }
      console.log('sending query');
      return true;
    };
    options.complete = function(data, textStatus) {
      localCache.set(url, data, complete);
    };
  }
});

function handleAjaxRequests(url, parameters, headers, method, successHandler, options, errorHandler) {
  method = method || "GET";
  headers = headers || {};
  parameters = parameters || {};

  return $.ajax({
    method: method.toUpperCase(),
    url: url,
    cache: true,
    //            async: false,
    data: parameters,
    headers: headers,
    success: successHandler,
    error: errorHandler,
  });
}

handleAjaxRequests('/echo/json/', {p1: 'hey'}, null, 'POST', function(data){console.log('first success without cache', data);});

setTimeout(function(){
handleAjaxRequests('/echo/json/', {p1: 'hey'}, null, 'POST', function(data){console.log('success! with cache hopefully', data);});
}, 2000);

Fiddle here

  1. added some logs in the localCache methods to see what's happening. Cache is never used so I've added the missing cache:true option
  2. Added some logs inside beforeSend method to monitor the toggle between cache and query. Everything works fine.
  3. Cleaned up the arguments null checks and removed empty function(){} (use $.noop() instead btw.
  4. Now the core of your issue. The callbacks errorHandler and successHandler are arguments. $.ajax is asynchronous! it means at some point of the execution, right after this call is made, you won't be sure if the variable has the same value. Easiest solution is to just reference the function directly and let jQuery do the scope management. Hardest solution would be to give these functions to the context option in ajax settings which I don't recommend.

Now, the solution you use allows you to directly call $.ajax without a wrapper method. Why don't you use it directly? simpler and less prone to errors


EDIT: I'm really not fond of context so there is another alternative.

function handleAjaxRequests(url, parameters, headers, method, successHandler, options, errorHandler) {
  method = method || "GET";
  headers = headers || {};
  parameters = parameters || {};

  return $.ajax({
    method: method.toUpperCase(),
    url: url,
    cache: true,
    //            async: false,
    data: parameters,
    headers: headers,
    success: (function(handler, opt) {
      return function( /*Anything*/ data, /*String*/ textStatus, /*jqXHR*/ jqXHR) {
        console.log('hi');
        handler(data, opt);
        console.log('bye');
      };
    })(successHandler, options),
    error: (function(handler, opt) {
      return function( /*jqXHR*/ jqXHR, /*String*/ textStatus, /*String*/ errorThrown) {
        console.log('ouch');
        handler(errorThrown);
      };
    })(errorHandler, options),
  });
}

You scope the function with this well known javascript trick aka currying.

New fiddle here.


EDIT 2: if you want successHandler to run even when getting from cache you should use complete instead of success

function handleAjaxRequests(url, parameters, headers, method, successHandler, options, errorHandler) {
  method = method || "GET";
  headers = headers || {};
  parameters = parameters || {};

  return $.ajax({
    method: method.toUpperCase(),
    url: url,
    cache: true,
    //            async: false,
    data: parameters,
    headers: headers,
    complete: (function(handler, opt) {
      return function( /*Anything*/ data, /*String*/ textStatus, /*jqXHR*/ jqXHR) {
        console.log('hi');
        handler(data, opt);
        console.log('bye');
      };
    })(successHandler, options),
    error: (function(handler, opt) {
      return function( /*jqXHR*/ jqXHR, /*String*/ textStatus, /*String*/ errorThrown) {
        console.log('ouch');
        handler(errorThrown);
      };
    })(errorHandler, options),
  });
}

Fiddle here.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.