AngularJS отключить частичное кэширование на компьютере разработчика

210

У меня есть проблема с кэшированием партиалов в AngularJS.

На моей странице HTML у меня есть:

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

где загружены мои партиалы.

Когда я изменяю HTML-код в своей части, браузер по-прежнему загружает старые данные.

Есть ли обходной путь?

Mennion
источник
4
Просто небольшое замечание: у меня была проблема с этим, которая была больше связана с заголовками контроля кэша, которые отправляло мое приложение Flask. Я обошел эту проблему, добавив app.config.update(SEND_FILE_MAX_AGE_DEFAULT=0)в мой flask_app.py. (Я думаю, что подобные вещи существуют для других веб-серверов).
gatoatigrado
4
Если вы используете chrome, просто сделайте Ctrl+Shift+R(т.е. Hard Reload), и независимо от того, какой механизм кэширования используется, chrome проигнорирует его и повторно загрузит все сценарии, таблицы стилей и т. Д.
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 Tools в правом нижнем углу нажмите на шестерню и отметьте опцию

Отключение кэш-памяти (в то время как Devtools открыта)

Обновление: в Firefox есть такая же опция в Отладчике -> Настройки -> Расширенный раздел (проверено на Версии 33)

Обновление 2: хотя эта опция появляется в Firefox, в некоторых отчетах она не работает. Я предлагаю использовать firebug и следующий ответ hadaytullah.

LukeSolar
источник
7
Это должен быть принятый ответ, потому что он не требует изменения кода и более важен для запроса ОП. Конечно, вы хотели бы, чтобы производственное приложение кешировало запросы, поэтому выполнение того, что предложили вышеупомянутые люди, хотя и имеет смысл, может оказаться проблематичным, если код останется в производственном приложении.
Аарон Вагнер
Какие-нибудь предложения для других браузеров как Firefox?
Lereveme
В Firefox: Отладчик> Настройки (шестеренка) есть такая же опция.
LukeSolar
5
Это не работает в Firefox. Даже когда кэш отключен и панель инструментов открыта, шаблоны все еще кэшируются.
Патрик Дж. Коллинз
4
Кеширование тоже влияет на производство? Что если я отправлю новые веб-файлы на сервер, что мешает последующим запросам от производственных клиентов загрузить предварительно опубликованные кэшированные версии?
Влияние
111

Опираясь на ответ @ Valentyn, вот один из способов всегда автоматически очищать кеш при каждом изменении содержимого ng-view:

myApp.run(function($rootScope, $templateCache) {
   $rootScope.$on('$viewContentLoaded', function() {
      $templateCache.removeAll();
   });
});
Марк Райкок
источник
@ user252690 Вероятно, также необходимо убедиться, что HTML-шаблон не был отправлен с заголовками кэша. Смотрите здесь и здесь для возможных исправлений
Крис Фостер
30
Небольшое предупреждение: очистка $ templateCache может привести к непредвиденным последствиям. Например, пользовательский интерфейс Bootstrap добавляет стандартные значения непосредственно в $ templateCache во время инициализации и позже ожидает, что они будут там.
Стрилл
@ Strille Я пытался использовать angular-ui-bootstrap Modal. Всплывающее окно не было видно. потому что $ templateCache.removeAll (); какое-нибудь решение для этого?
Мукун
4
@Mukun: не так просто исправить то, как я это вижу, кроме как не использовать removeAll (), а вместо этого просто использовать remove () для удаления ключей, которые нужно очистить. Вам потребуется какая-то бухгалтерия, чтобы знать, какие ключи удалить.
Стрилл
Есть ли способы очистить кеш только для конкретного пользовательского интерфейса просмотра кеша.
Гаян
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. Рядом с «Net» (заголовок представления) появится символ выпадающего меню.
  4. Выберите «Отключить кэш браузера» в раскрывающемся меню.
hadaytullah
источник
Пробовал на 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/

Код розыгрыша
источник
Ниппик, но когда ток вообще не объект? Не уверен, что его там тоже нет, ноif (!current) { return; }
Нейт-Уилкинс
Это побеждает кеширование Angular шаблонов на основе маршрутов, но не партиций ng-include'd.
bradw2k
16

Я публикую это просто для того, чтобы охватить все возможности, так как ни одно из других решений не работало для меня (среди прочего, они выдавали ошибки из-за зависимостей шаблона angular-bootstrap).

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

       $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переменной.

diosney
источник
1
Позже вы можете установить, .value('DEBUG', true)чтобы включить эту строку или нет.
diosney
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», правда)? Upvoted!
JackLeEmmerdeur
Использование .value('DEBUG', trueтакое же, как и у вас $rootScope, но без загромождения :) Позже вы можете внедрить DEBUGв контроллер и запросить как обычный сервис.
diosney
Не могли бы вы расширить исходный код в своем ответе, включив в него что- .value(...)нибудь, если это не слишком сложно? Я полагаю, что эта концепция представляет собой угловую лучшую практику, неизвестную мне.
JackLeEmmerdeur
1
Это решение очень полезно при работе с Ionic. Это сэкономит мне столько времени, что снова сделает livereload полезным. Благодаря тонну!
ajuser
11

Как уже говорили другие, победить кеширование полностью для целей разработки можно легко, не меняя код: используйте настройки браузера или плагина. Вне dev, чтобы победить кэширование шаблонов Angular шаблонами на основе маршрутов, удалите URL шаблона из кэша во время $ routeChangeStart (или $ stateChangeStart для UI Router), как показал Шаян. Однако это НЕ влияет на кэширование шаблонов, загружаемых с помощью 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;
    }
bradw2k
источник
Меня интересует ваше решение - сохраняете ли вы этот код навсегда или в течение определенного периода времени после внесения изменений? Причина - будет беспокоиться о производительности. Кроме того, вы упоминаете побочные эффекты побеждает HTTP. Вы имеете в виду, что это хороший способ побочных эффектов - значит, это то, что вы и хотели, чтобы иметь «исправление»? Thx
jamie
1
Я оставляю этот код навсегда, хотя мы сократили продолжительность очистки кеша до 10 минут. Таким образом, каждые 10 минут использования пользователь будет перезагружать свежие HTML-шаблоны. Для моего бизнес-приложения это приемлемая цена за приобретение возможности оперативного исправления шаблонов, но, очевидно, это слишком сильно ухудшит производительность для некоторых типов приложений. ... К сожалению, кеширование HTTP также побеждено, но я не вижу способа разумно победить кеширование шаблонов Angular, не победив etag и т. Д. Кэширование шаблонов IMO Angular просто недостаточно настраивается.
bradw2k
1
+1 У меня была та же идея, но я перехватывал только для localhost. Вы можете увидеть мою реализацию перехватчика здесь: overengineer.net/…
joshcomley
@joshcomley Если вам нужно победить только кэширование на localhost, почему бы не использовать плагин для браузера, который побеждает все кэширование?
bradw2k
@ Bradw2k Таким образом, я полностью контролирую то, что кэшируется, а что нет, что может быть полезно для разработки. Я также тестирую во всех браузерах, и не во всех браузерах есть расширения, которые делают то, что мне нужно. У меня также может быть индикатор на сайте в разработке, показывающий, отключено ли кэширование, так как иногда я хочу отключить и протестировать несколько браузеров на некоторое время.
Джошкомли
8

Если вы используете UI-маршрутизатор, вы можете использовать декоратор и обновить службу $ 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.

Вот как выглядит метод dev cachebusting 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');
}]);
cpreid
источник
1

Вот еще один вариант в Chrome.

Нажмите, F12чтобы открыть инструменты разработчика. Затем Ресурсы > Хранилище кэша > Обновить кэши .

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

Мне нравится эта опция, потому что мне не нужно отключать кеш, как в других ответах.

Джесс
источник
В Chrome v. 54.0.2840.99 в ноябре 2016 года я обнаружил это на вкладке «Приложение», а не «Ресурсы».
StackOverflowUser
0

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

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

Томас Деко
источник