2013-06-14 3 views
66

Я хотел бы включить кеширование ответа ajax в javascript/browser.Кэширование jQuery ajax-ответа в javascript/browser

Из jquery.ajax docs:

По умолчанию запросы всегда выдаются, но браузер может служить результаты из кэша. Чтобы запретить использование кэшированных результатов, установите для кеша значение false. Чтобы заставить запрос сообщить о сбое, если актив не был изменен со времени последнего запроса, установите ifModified в true.

Однако ни один из этих адресов не требует кэширования.

Мотивация: Я хочу поставить $.ajax({...}) вызовы в моей инициализации функций, некоторые из которых запрашивают один и тот же URL. Иногда мне нужно вызвать одну из этих функций инициализации, иногда я вызываю несколько.

Итак, я хочу свести к минимуму запросы на сервер, если этот конкретный URL уже загружен.

Я мог бы свернуть свое решение (с некоторым трудом!), Но я хотел бы знать, есть ли стандартный способ сделать это.

+0

Я бы не подумал, что трудности, чтобы отслеживать какие ссылки вы уже загружены и сохранить результаты в отношении этого списка. Затем вы можете проверить свои URL-адреса, прежде чем совершать AJAX-вызов. Voila - у вас есть свой основной кеш. –

+0

вы можете добавить кэш-контроль и завершить заголовок для ответа на сервере, поэтому ваш сервер должен вызываться только после таймаута, настроенного в этих значениях – hereandnow78

ответ

111

cache:true работает только с запросом GET и HEAD.

Вы можете свернуть свои собственные решения, как вы сказали, с чем-то вдоль этих линий:

var localCache = { 
    data: {}, 
    remove: function (url) { 
     delete localCache.data[url]; 
    }, 
    exist: function (url) { 
     return localCache.data.hasOwnProperty(url) && localCache.data[url] !== null; 
    }, 
    get: function (url) { 
     console.log('Getting in cache for url' + url); 
     return localCache.data[url]; 
    }, 
    set: function (url, cachedData, callback) { 
     localCache.remove(url); 
     localCache.data[url] = cachedData; 
     if ($.isFunction(callback)) callback(cachedData); 
    } 
}; 

$(function() { 
    var url = '/echo/jsonp/'; 
    $('#ajaxButton').click(function (e) { 
     $.ajax({ 
      url: url, 
      data: { 
       test: 'value' 
      }, 
      cache: true, 
      beforeSend: function() { 
       if (localCache.exist(url)) { 
        doSomething(localCache.get(url)); 
        return false; 
       } 
       return true; 
      }, 
      complete: function (jqXHR, textStatus) { 
       localCache.set(url, jqXHR, doSomething); 
      } 
     }); 
    }); 
}); 

function doSomething(data) { 
    console.log(data); 
} 

Working fiddle here

EDIT: поскольку этот пост станет популярным, здесь даже лучше ответ для тех, кто хочет управляйте тайм-аутом, и вам также не нужно беспокоиться о том, что в $.ajax() я использую $.ajaxPrefilter(). Теперь просто установка {cache: true} достаточно для обработки кэш правильно:

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() { 
    var url = '/echo/jsonp/'; 
    $('#ajaxButton').click(function (e) { 
     $.ajax({ 
      url: url, 
      data: { 
       test: 'value' 
      }, 
      cache: true, 
      complete: doSomething 
     }); 
    }); 
}); 

function doSomething(data) { 
    console.log(data); 
} 

And the fiddle hereОСТОРОЖНЫ, не работает с $ .Deferred

Вот рабочий, но недостатки реализации работы с отложила:

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) { 
     //Here is our identifier for the cache. Maybe have a better, safer ID (it depends on the object string representation here) ? 
     // on $.ajax call we could also set an ID in originalOptions 
     var id = originalOptions.url+ JSON.stringify(originalOptions.data); 
     options.cache = false; 
     options.beforeSend = function() { 
      if (!localCache.exist(id)) { 
       jqXHR.promise().done(function (data, textStatus) { 
        localCache.set(id, data); 
       }); 
      } 
      return true; 
     }; 

    } 
}); 

$.ajaxTransport("+*", function (options, originalOptions, jqXHR, headers, completeCallback) { 

    //same here, careful because options.url has already been through jQuery processing 
    var id = originalOptions.url+ JSON.stringify(originalOptions.data); 

    options.cache = false; 

    if (localCache.exist(id)) { 
     return { 
      send: function (headers, completeCallback) { 
       completeCallback(200, "OK", localCache.get(id)); 
      }, 
      abort: function() { 
       /* abort code, nothing needed here I guess... */ 
      } 
     }; 
    } 
}); 

$(function() { 
    var url = '/echo/jsonp/'; 
    $('#ajaxButton').click(function (e) { 
     $.ajax({ 
      url: url, 
      data: { 
       test: 'value' 
      }, 
      cache: true 
     }).done(function (data, status, jq) { 
      console.debug({ 
       data: data, 
       status: status, 
       jqXHR: jq 
      }); 
     }); 
    }); 
}); 

Fiddle HERE Некоторые проблемы, наш идентификатор кеша зависит от представления объекта Json2 lib JSON.

Используйте консольный вид (F12) или FireBug для просмотра некоторых журналов, сгенерированных кешем.

+0

, есть причина, по которой вы поместить обратный вызов в функцию 'localCache.set'? Почему не просто 'doSomehing (jqXHR)' после установки кеша? – cammil

+0

Я просто предпочитаю это таким образом, поэтому мне не нужно делать что-то вроде 'doSomething (localCache.set (url, jqXHR));' но это просто личное предпочтение – TecHunter

+0

объяснить, почему downvote? – TecHunter

3

Если я понял ваш вопрос, вот решение:

$.ajaxSetup({ cache: true}); 

и для конкретных вызовов

$.ajax({ 
     url: ..., 
     type: "GET", 
     cache: false,   
     ... 
    }); 

Если вы хотите, напротив (кэш для определенных вызовов) вы можете установить ложь в начале и верно для конкретных вызовов.

+0

, это точно противоположное – TecHunter

+0

. Я отредактировал ответ – spring

4

Все современные браузеры предоставляют вам память apis. Вы можете использовать их (localStorage или sessionStorage) для сохранения ваших данных.

Все, что вам нужно сделать, это получить ответное хранилище в хранилище браузера. Затем в следующий раз, когда вы найдете тот же вызов, выполните поиск, если ответ уже сохранен. Если да, верните ответ оттуда; если не сделать новый звонок.

Smartjax плагин также делает подобные вещи; но поскольку ваше требование просто сохраняет ответ на вызов, вы можете написать свой код внутри вашей функции jQuery ajax success, чтобы сохранить ответ. И перед вызовом просто проверьте, сохранен ли ответ.

8

Я искал кеширование для своего приложения для хранения телефонных разговоров, и я нашел ответ @TecHunter, который велик, но с использованием localCache.

Я нашел и узнал, что localStorage - это еще одна альтернатива кешированию данных, возвращаемых вызовом ajax. Итак, я создал одно демо, используя localStorage, который поможет другим пользователям, которые могут использовать localStorage вместо localCache для кеширования.

Ajax вызовов:

$.ajax({ 
    type: "POST", 
    dataType: 'json', 
    contentType: "application/json; charset=utf-8", 
    url: url, 
    data: '{"Id":"' + Id + '"}', 
    cache: true, //It must "true" if you want to cache else "false" 
    //async: false, 
    success: function (data) { 
     var resData = JSON.parse(data); 
     var Info = resData.Info; 
     if (Info) { 
      customerName = Info.FirstName; 
     } 
    }, 
    error: function (xhr, textStatus, error) { 
     alert("Error Happened!"); 
    } 
}); 

Для хранения данных в LocalStorage:

$.ajaxPrefilter(function (options, originalOptions, jqXHR) { 
if (options.cache) { 
    var success = originalOptions.success || $.noop, 
     url = originalOptions.url; 

    options.cache = false; //remove jQuery cache as we have our own localStorage 
    options.beforeSend = function() { 
     if (localStorage.getItem(url)) { 
      success(localStorage.getItem(url)); 
      return false; 
     } 
     return true; 
    }; 
    options.success = function (data, textStatus) { 
     var responseData = JSON.stringify(data.responseJSON); 
     localStorage.setItem(url, responseData); 
     if ($.isFunction(success)) success(responseJSON); //call back to original ajax call 
    }; 
} 
}); 

Если вы хотите удалить LocalStorage, используйте следующее заявление, где вы хотите:

localStorage.removeItem("Info"); 

Надеюсь, это поможет другим!

+0

Привет, в 'localStorage.removeItem (« Информация »);', о '' info ''это url? – vsogrimen

+0

@vsogrimen 'info' является объектом хранения данных в localStorage. –

+1

продолжать получать 'responseJSON не определен'. Любой способ исправить это? (мой тип данных - html) – CreativeMind

0

Старый вопрос, но мое решение немного другое.

Я писал одностраничное веб-приложение, которое постоянно вызывало вызовы ajax, вызванные пользователем, и для его еще более сложного требовались библиотеки, в которых использовались методы, отличные от jquery (например, dojo, native xhr и т. Д.). Я написал плагин для одного из my own libraries для кэширования ajax-запросов как можно эффективнее таким образом, чтобы он работал во всех основных браузерах, независимо от того, какие библиотеки использовались для вызова ajax.

Раствор использует jSQL (написанный мной - реализация стойких SQL на сторону клиента написано в JavaScript, который использует индексированный и другие методы хранения дома), и в комплекте с другой библиотекой называется XHRCreep (написанный мной), который является полным перезаписать собственный объект XHR.

Чтобы реализовать все, что вам нужно сделать, это включить плагин на вашей странице, which is here.

Есть два варианта:

jSQL.xhrCache.max_time = 60; 

Установите максимальный возраст в течение нескольких минут. все кэшированные ответы, которые старше этого, запрашиваются повторно. Значение по умолчанию - 1 час.

jSQL.xhrCache.logging = true; 

Если установлено значение true, на консоль для отладки будут показаны ложные вызовы XHR.

Вы можете очистить кэш на любой странице с помощью

jSQL.tables = {}; jSQL.persist(); 
Смежные вопросы