AngularJS відключить часткове кешування на машині розробки


210

У мене проблеми з кешуванням партій у AngularJS.

На моїй HTML-сторінці я маю:

<body>
 <div ng-view></div>
<body>

де завантажені мої партії.

Коли я змінюю HTML-код у своєму частковому, браузер все ще завантажує старі дані.

Чи є якесь вирішення?


4
Лише швидка примітка: у мене виникла проблема з цим, що було більше пов’язане із заголовками кеш-керування, які моя програма Flask надсилала назад. Я вирішив проблему, додавши app.config.update(SEND_FILE_MAX_AGE_DEFAULT=0)до свого flask_app.py. (Я думаю, подібні речі існують і для інших веб-серверів).
gatoatigrado

4
Якщо ви використовуєте хром, просто виконайте Ctrl+Shift+R(тобто Hard Reload), і незалежно від того, який механізм кешування використовується, хром проігнорує його та повторно отримає всі сценарії, таблиці стилів тощо
snajahi

4
ctrl + shift + R не працює для мене в Chrome, але на вкладці інструментів розробника "мережа" натискання на "відключити кеш" працює чудово. Для мене це проблема клієнта, яку не слід вирішити за допомогою хак на сервері, як і багато пропозицій нижче; його слід зафіксувати на клієнті, де існує "проблема". Якщо ви виправите це на сервері та забудете його виправити, виробництво може негативно вплинути.
Мурашка Кучера

8
ctrl + shift + R обходить кеш для звичайних запитів. запити ajax, зроблені з кутових для ng-include| ng-view| templateUrlця ярлик не обробляється
Андре Верланг

2
Ви не можете задавати всім кінцевим користувачам Ctrl + Shift + R під час відвідування сайту, тож яка відповідь на це питання для випадку, що не стосується розробки? "Для мене це проблема клієнта, яку не слід вирішити за допомогою хак на сервері, як і багато пропозицій нижче" - Я не згоден, ви не можете контролювати клієнтів у веб-середовищі, тому виправлення для виробництва повинні керуватися додатком. З цієї причини я прийняв: $ rootScope. $ On ('$ viewContentLoaded', function () {$ templateCache.removeAll ();});
Роберт Крістіан

Відповіді:


200

Для розробки ви також можете відключити кеш браузера - в Інструментах Chrome Dev в нижньому правому куті клацніть на шестірні та позначте опцію

Вимкнути кеш-пам'ять (поки DevTools відкритий)

Оновлення: у Firefox є однаковий варіант у налагоджувачі -> Налаштування -> Розширений розділ (перевірено на версію 33)

Оновлення 2: Хоча ця опція з’являється у Firefox, у деякому звіті вона не працює. Я пропоную використовувати firebug та наступну відповідь хадайтулла.


7
Це повинно бути прийнятою відповіддю, оскільки воно не вимагає зміни коду, і більше відповідає вимозі ОП. Звичайно, ви хочете, щоб виробничий додаток кешував запити, тому робити те, що запропонували вищезгадані люди, але, маючи на увазі, може виявитися проблематичним, якщо код залишити у виробничому додатку.
Аарон Вагнер

Будь-які пропозиції для інших браузерів, таких як Firefox?
Леревеме

У Firefox: Debugger> Settings (передача) є однаковий варіант.
LukeSolar

5
У Firefox це не працює. Навіть коли кеш вимкнено, а панель інструментів відкрита, шаблони все ще кешуються.
Патрік Дж. Коллінз

4
Чи впливає кешування також на виробництво? Що робити, якщо я натискаю нові веб-файли на сервер, що заважає наступним запитам виробничих клієнтів завантажувати попередньо опубліковані кешовані версії?
meffect

111

Спираючись трохи на відповідь @ Valentyn, ось один із способів завжди автоматично очистити кеш-пам'ять, коли зміст вмісту ng-перегляду змінюється:

myApp.run(function($rootScope, $templateCache) {
   $rootScope.$on('$viewContentLoaded', function() {
      $templateCache.removeAll();
   });
});

@ user252690 Напевно, також потрібно переконатися, що шаблон HTML не надісланий із заголовками кеша. Дивіться тут і тут можливі виправлення
Кріс Фостер,

30
Трохи попередження: спорожнення $ templateCache може насправді мати ненавмисні наслідки. Наприклад, UI Bootstrap додає частинки за замовчуванням безпосередньо до $ templateCache під час ініціалізації та пізніше очікує їх наявності.
Strille

@Strille Я намагався використовувати Modular-ui-bootstrap Modal. Спливаюче вікно не було видно тому що $ templateCache.removeAll (); якісь виправлення на це?
Мукун

4
@Mukun: Неможливо легко виправити те, як я це бачу, окрім того, щоб не використовувати RemoveAll (), а натомість просто видалити () для видалення ключів, які потрібно очистити. Вам знадобиться якась бухгалтерія, щоб знати, які ключі видалити.
Strille

чи є способи очищення кешу лише для певного кешу перегляду інтерфейсу.
Гаян

37

Як зазначено в інших відповідях, тут і тут кеш можна очистити за допомогою:

$templateCache.removeAll();

Однак, як запропонував gatoatigrado у коментарі , це, здається, працює лише в тому випадку, якщо шаблон HTML подається без заголовків кешу.

Отже, це працює для мене:

У кутовій:

app.run(['$templateCache', function ( $templateCache ) {
    $templateCache.removeAll(); }]);

Ви можете додавати заголовки кешу різними способами, але ось декілька рішень, які працюють для мене.

Якщо ви користуєтесь IIS, додайте це до свого web.config:

<location path="scripts/app/views">
  <system.webServer>
    <staticContent>
      <clientCache cacheControlMode="DisableCache" />
    </staticContent>
  </system.webServer>
</location>

Якщо ви використовуєте Nginx, ви можете додати це до своєї конфігурації:

location ^~ /scripts/app/views/ {
    expires -1;   
}

Редагувати

Я просто зрозумів, що питання, про яке згадується devмашина, але, сподіваюся, це все ще може допомогти комусь ...


2
так, навіть якщо це не відповідає на оригінальне запитання безпосередньо, це насправді допомогло мені вирішити проблему кешування на веб-сайті, що живе в реальному часі.
Андре

31

Якщо ви говорите про кеш, який використовується для кешування шаблонів без перезавантаження цілої сторінки, ви можете випорожнити її чимось на зразок:

.controller('mainCtrl', function($scope, $templateCache) {
  $scope.clearCache = function() { 
    $templateCache.removeAll();
  }
});

І в розмітці:

<button ng-click='clearCache()'>Clear cache</button>

І натисніть цю кнопку, щоб очистити кеш.


22

Рішення для Firefox (33.1.1) за допомогою Firebug (22.0.6)

  1. Інструменти> Веб-інструменти> Firebug> Відкрити Firebug.
  2. У Firebug подання переходить до перегляду "Net".
  3. Символ випадаючого меню з’явиться поруч із пунктом «Чистий» (назва перегляду).
  4. Виберіть "Вимкнути кеш браузера" зі спадного меню.

Пробували на Firebug (2.0.11) та Firefox (38.0.1) на mac, але це не спрацювало.
paullb

19

Цей фрагмент допоміг мені позбутися кешування шаблонів

app.run(function($rootScope, $templateCache) {
    $rootScope.$on('$routeChangeStart', function(event, next, current) {
        if (typeof(current) !== 'undefined'){
            $templateCache.remove(current.templateUrl);
        }
    });
});

Деталі наступного фрагмента можна знайти за цим посиланням: http://oncodesign.io/2014/02/19/safely-prevent-template-caching-in-angularjs/


nitpick, але коли струм ніколи не є об'єктом? Не впевнений, що його теж ніколи немає, алеif (!current) { return; }
Nate-Wilkins

Це перемагає Angular кешування шаблонів на основі маршруту, але не ng-include'd partials.
bradw2k

16

Я публікую це лише для того, щоб охопити всі можливості, оскільки жодне з інших рішень для мене не працювало (серед інших вони викидали помилки через залежність шаблону кутового завантаження).

Під час розробки / налагодження певного шаблону ви можете переконатися, що він завжди оновлюється, включивши в шлях часову позначку, як це:

       $modal.open({
          // TODO: Only while dev/debug. Remove later.
          templateUrl: 'core/admin/organizations/modal-selector/modal-selector.html?nd=' + Date.now(),
          controller : function ($scope, $modalInstance) {
            $scope.ok = function () {
              $modalInstance.close();
            };
          }
        });

Зазначимо фінал ?nd=' + Date.now()у templateUrlзмінній.


1
Пізніше ви можете встановити а, .value('DEBUG', true)щоб увімкнути цей рядок чи ні.
діосней

1
Моє рішення було використовувати наступне в фазі ініціалізації мого основного модуля під , .run(function($rootScope) { $rootScope.DEBUG = true; ...а потім в директиві впорскувати $ rootScope , як .directive('filter', ['$rootScope', function($rootScope)...і в повернутому об'єкті-властивості: templateUrl: '/app/components/filter/filter-template.html' + ($rootScope.DEBUG ? '?n=' + Date.now() : ''). Можливо, ви могли б розробити свій .value ("DEBUG", правда) підхід? Оголошено!
JackLeEmmerdeur

Використання .value('DEBUG', trueте саме, що ви робили з $rootScope, але не захаращуючи це :) Ви згодом можете вводити DEBUGв контролер і запитувати як звичайний сервіс.
діосней

Чи можете ви, можливо, розширити вихідний код у своїй відповіді, щоб включити все .value(...), що це не дуже складно? Я гадаю, що концепція є кутовою найкращою практикою, невідомою мені.
JackLeEmmerdeur

1
Це рішення дуже корисне при роботі з Ionic. Це заощадить мені стільки часу, як знову зробить завантаження корисним. Дякую тонну!
аюсер

11

Як говорили інші, перемогти кешування повністю для цілей розробника можна легко, не змінюючи код: використовуйте налаштування браузера або плагін. Поза межами dev, щоб перемогти кутовий кешування шаблонів шаблонів на основі маршруту, видаліть URL-адресу шаблону з кеша під час $ routeChangeStart (або $ stateChangeStart, для маршрутизатора інтерфейсу користувача), як показав Шаян. Однак це НЕ впливає на кешування шаблонів, завантажених ng-include, оскільки ці шаблони не завантажуються через маршрутизатор.

Я хотів мати можливість виправляти будь-який шаблон, у тому числі завантажений ng-include, у виробництві, і користувачі отримують виправлення у своєму браузері швидко, не потребуючи перезавантаження всієї сторінки. Мене також не турбує поразка кешування HTTP для шаблонів. Рішення полягає в тому, щоб перехопити кожен запит HTTP, який робить додаток, ігнорувати ті, які не є шаблонами .html мого додатка, а потім додати параметр до URL-адреси шаблону, яка змінюється щохвилини. Зауважте, що перевірка шляху є специфічною для шляху шаблонів вашого додатка. Щоб отримати інший інтервал, змініть математику для параметра або видаліть% повністю, щоб не отримати кешування.

// this defeats Angular's $templateCache on a 1-minute interval
// as a side-effect it also defeats HTTP (browser) caching
angular.module('myApp').config(function($httpProvider, ...) {
    $httpProvider.interceptors.push(function() {
        return {
            'request': function(config) {
                config.url = getTimeVersionedUrl(config.url);
                return config;
            }
        };
    });

    function getTimeVersionedUrl(url) {
        // only do for html templates of this app
        // NOTE: the path to test for is app dependent!
        if (!url || url.indexOf('a/app/') < 0 || url.indexOf('.html') < 0) return url;
        // create a URL param that changes every minute
        // and add it intelligently to the template's previous url
        var param = 'v=' + ~~(Date.now() / 60000) % 10000; // 4 unique digits every minute
        if (url.indexOf('?') > 0) {
            if (url.indexOf('v=') > 0) return url.replace(/v=[0-9](4)/, param);
            return url + '&' + param;
        }
        return url + '?' + param;
    }

Мене цікавить ваше рішення - чи зберігаєте ви цей код назавжди - чи певний проміжок часу після внесення змін? Причина - буде стурбована продуктивністю. Також ви згадуєте побічні поразки HTTP. Ви маєте на увазі, що це правильний побічний спосіб коректного - тобто це те, що ви задумали, щоб мати «виправлення»? Thx
jamie

1
Я залишаю цей код назавжди, хоча ми набрали тривалість кеш-пам’яті до 10 хвилин. Тож кожні 10 хвилин використання користувач буде перезавантажувати свіжі шаблони html. Для мого додатка biz це прийнятна вартість, щоб отримати можливість шаблонів гарячих патчів, але, очевидно, це може погіршити продуктивність для деяких видів додатків. ... Прикро, що HTTP-кешування також зазнає поразки, але я не бачу способу інтелектуально перемогти кешоване шаблонне шаблонне шаблонне зображення, не переможачи також етагів тощо. Кутове кешування шаблонів IMO просто недостатньо конфігурується.
bradw2k

1
+1 У мене була така ж ідея, але я перехоплюю лише localhost. Ви можете побачити мою реалізацію перехоплювача тут: overengineer.net/…
joshcomley

@joshcomley Якщо вам потрібно лише перемогти кешування на localhost, чому б не використовувати плагін браузера, який перемагає всі кешування?
bradw2k

@ bradw2k таким чином я повністю контролюю те, що є, а не кешоване, що може бути корисно для розвитку. Я також тестую у всіх браузерах, і не у всіх браузерах є розширення, які роблять те, що мені потрібно. Я також можу мати показник на сайті в розробці, який підкаже мені, чи кешування вимкнено чи не, оскільки іноді я хочу лише на деякий час відключити і протестувати в браузерах.
Джошкомлі

8

Якщо ви використовуєте маршрутизатор інтерфейсу користувача, ви можете використовувати декоратор та оновити $ templateFactory службу та додати параметр рядка запиту до templateUrl, і браузер завжди завантажить новий шаблон із сервера.

function configureTemplateFactory($provide) {
    // Set a suffix outside the decorator function 
    var cacheBust = Date.now().toString();

    function templateFactoryDecorator($delegate) {
        var fromUrl = angular.bind($delegate, $delegate.fromUrl);
        $delegate.fromUrl = function (url, params) {
            if (url !== null && angular.isDefined(url) && angular.isString(url)) {
                url += (url.indexOf("?") === -1 ? "?" : "&");
                url += "v=" + cacheBust;
            }

            return fromUrl(url, params);
        };

        return $delegate;
    }

    $provide.decorator('$templateFactory', ['$delegate', templateFactoryDecorator]);
}

app.config(['$provide', configureTemplateFactory]);

Я впевнений, що ви можете досягти такого ж результату, прикрасивши метод "коли" в $ routeProvider.


Набагато кращою альтернативою є використання плагіна на зразок gulp-angular-templatecache для реєстрації кутових js-шаблонів у $ templateCache. Це слід використовувати разом з gulp-rev. Щоразу, коли шаблон змінюється, буде створений новий файл JavaScript з іншим номером версії, а кешування ніколи не буде проблемою.
Аман Махаджан

3

Я виявив, що метод перехоплювача HTTP працює досить непогано і дозволяє отримати додаткову гнучкість та контроль. Крім того, ви можете кешувати бюст для кожного випуску виробництва, використовуючи хеш випуску як змінну buster.

Ось як виглядає використання методу кешбестрування розробників Date.

app.factory('cachebustInjector', function(conf) {   
    var cachebustInjector = {
        request: function(config) {    
            // new timestamp will be appended to each new partial .html request to prevent caching in a dev environment               
            var buster = new Date().getTime();

            if (config.url.indexOf('static/angular_templates') > -1) {
                config.url += ['?v=', buster].join('');
            }
            return config;
        }
    };
    return cachebustInjector;
});

app.config(['$httpProvider', function($httpProvider) {
    $httpProvider.interceptors.push('cachebustInjector');
}]);

1

Ось ще один варіант у Chrome.

Натисніть, F12щоб відкрити інструменти для розробників. Потім Ресурси > Зберігання кешу > Оновити кеші .

введіть тут опис зображення

Мені подобається цей варіант, тому що мені не потрібно відключати кеш, як в інших відповідях.


У Chrome v. 54.0.2840.99 у листопаді 2016 року я виявив це на вкладці під назвою Application.rather than Resources.
StackOverflowUser

0

Немає рішення для запобігання кешування браузера / проксі, оскільки ви не можете керувати ним.

Інший спосіб змусити ваших користувачів свіжий вміст перейменувати HTML-файл! Так само, як і https://www.npmjs.com/package/grunt-filerev для активів.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.