AngularJS wyłącza częściowe buforowanie na urządzeniu deweloperskim

210

Mam problem z buforowaniem części w AngularJS.

Na mojej stronie HTML mam:

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

gdzie są ładowane moje częściowe.

Kiedy zmieniam kod HTML w częściowym, przeglądarka nadal ładuje stare dane.

Czy istnieje jakieś obejście?

Mennion
źródło
4
Krótka uwaga: miałem z tym problem, który był bardziej związany z nagłówkami kontroli pamięci podręcznej, które moja aplikacja Flask odsyła. Obejrzałem ten problem, dodając app.config.update(SEND_FILE_MAX_AGE_DEFAULT=0)do mojego flask_app.py. (Wyobrażam sobie, że podobne rzeczy istnieją w przypadku innych serwerów sieciowych).
gatoatigrado
4
Jeśli używasz chrome, po prostu zrób Ctrl+Shift+R(tj. Hard Reload) i bez względu na to, jaki mechanizm buforowania zostanie użyty, chrome zignoruje go i ponownie pobierze wszystkie skrypty, arkusze stylów itp.
snajahi
4
ctrl + shift + R nie działa dla mnie w Chrome, ale na karcie „sieć” narzędzi programisty kliknięcie „wyłącz pamięć podręczną” działa idealnie. Dla mnie jest to problem po stronie klienta, którego nie należy rozwiązywać za pomocą hacków na serwerze, jak wiele poniższych sugestii; należy to naprawić na kliencie, w którym istnieje „problem”. Jeśli naprawisz to na serwerze i zapomnisz go naprawić, może to mieć negatywny wpływ na produkcję.
Ant Kutschera,
8
ctrl + shift + R pomija pamięć podręczną dla normalnych żądań. żądania ajax wykonane z kątownika dla ng-include| ng-view| templateUrlskrót nie jest obsługiwany
André Werlang
2
Nie możesz poprosić wszystkich użytkowników końcowych o Ctrl + Shift + R podczas odwiedzania witryny, więc jaka jest odpowiedź na to pytanie w przypadku nierozwojowym? „Dla mnie jest to problem po stronie klienta, którego nie należy rozwiązywać za pomocą hacków na serwerze, jak wiele z poniższych sugestii” - nie zgadzam się, nie można kontrolować klientów w środowisku internetowym, więc poprawka dotycząca produkcji musi być sterowany aplikacją. Z tego powodu zaakceptowałem: $ rootScope. $ On ('$ viewContentLoaded', function () {$ templateCache.removeAll ();});
Robert Christian

Odpowiedzi:

200

Dla programistów możesz także dezaktywować pamięć podręczną przeglądarki - w Chrome Dev Tools w prawym dolnym rogu kliknij koło zębate i zaznacz opcję

Wyłącz pamięć podręczną (gdy DevTools jest otwarte)

Aktualizacja: W przeglądarce Firefox dostępna jest ta sama opcja w Debuggerze -> Ustawienia -> Sekcja zaawansowana (zaznaczona dla wersji 33)

Aktualizacja 2: Chociaż ta opcja pojawia się w Firefoksie, niektóre raporty nie działają. Sugeruję użycie firebuga i skorzystanie z odpowiedzi hadaytullah.

LukeSolar
źródło
7
To powinna być zaakceptowana odpowiedź, ponieważ nie wymaga zmiany kodu i jest bardziej zbliżona do żądania OP. Oczywiście chciałbyś, aby aplikacja produkcyjna buforowała żądania, więc robienie tego, co sugerują powyższe osoby, choć dobre znaczenie, może okazać się problematyczne, jeśli kod pozostanie w aplikacji produkcyjnej.
Aaron Wagner
Wszelkie sugestie dotyczące innych przeglądarek, takich jak Firefox?
Lereveme
W przeglądarce Firefox: Debugger> Ustawienia (koło zębate) dostępna jest ta sama opcja.
LukeSolar
5
To nie działa w przeglądarce Firefox. Nawet gdy pamięć podręczna jest wyłączona, a zestaw narzędzi jest otwarty, szablony są nadal buforowane.
Patrick J Collins,
4
Czy buforowanie wpływa również na produkcję? Co się stanie, jeśli wypchnę nowe pliki internetowe na serwer, co uniemożliwi kolejnym żądaniom klientów produkcyjnych ładowanie wcześniej opublikowanych wersji buforowanych?
skuteczny
111

Opierając się nieco na odpowiedzi @ Valentyn, oto jeden ze sposobów automatycznego czyszczenia pamięci podręcznej za każdym razem, gdy zmienia się zawartość widoku ng:

myApp.run(function($rootScope, $templateCache) {
   $rootScope.$on('$viewContentLoaded', function() {
      $templateCache.removeAll();
   });
});
Mark Rajcok
źródło
@ user252690 Prawdopodobnie trzeba również upewnić się, że szablon HTML nie został wysłany z nagłówkami pamięci podręcznej. Zobacz tutaj i tutaj możliwe poprawki
Chris Foster
30
Trochę ostrzeżenia: Opróżnienie $ templateCache może mieć rzeczywiście niezamierzone konsekwencje. Na przykład UI Bootstrap dodaje domyślne częściowe bezpośrednio do $ templateCache podczas inicjalizacji, a później oczekuje ich obecności.
Strille,
@Strille Próbowałem użyć modularnego modułu ui-bootstrap. Wyskakujące okienko nie było widoczne. ponieważ $ templateCache.removeAll (); jakaś poprawka na to?
Mukun,
4
@Mukun: Nie ma łatwego sposobu, w jaki ja to widzę, oprócz użycia removeAll (), ale zamiast tego użyj remove (), aby usunąć klucze, które musisz wyczyścić. Wymagałoby to jakiejś księgowości, aby wiedzieć, które klucze należy usunąć.
Strille,
czy istnieją sposoby na wyczyszczenie pamięci podręcznej tylko dla określonej pamięci podręcznej widoku interfejsu użytkownika?
Gayan
37

Jak wspomniano w innych odpowiedziach, tu i tutaj pamięć podręczną można wyczyścić za pomocą:

$templateCache.removeAll();

Jednak, jak sugeruje gatoatigrado w komentarzu , wydaje się, że działa to tylko wtedy, gdy szablon HTML był wyświetlany bez nagłówków pamięci podręcznej.

Więc to działa dla mnie:

Kątowe:

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

Możesz dodawać nagłówki pamięci podręcznej na różne sposoby, ale oto kilka rozwiązań, które działają dla mnie.

Jeśli używasz IIS, dodaj to do swojego web.config:

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

Jeśli używasz Nginx, możesz dodać to do swojej konfiguracji:

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

Edytować

Właśnie zdałem sobie sprawę, że pytanie dotyczy devmaszyny, ale mam nadzieję, że nadal może to komuś pomóc ...

Chris Foster
źródło
2
tak, chociaż nie odpowiada to bezpośrednio na pierwotne pytanie, w rzeczywistości pomogło mi to rozwiązać problem z buforowaniem w witrynie na żywo.
Andre
31

Jeśli mówisz o pamięci podręcznej używanej do buforowania szablonów bez ponownego ładowania całej strony, możesz ją opróżnić przez:

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

I w znacznikach:

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

I naciśnij ten przycisk, aby wyczyścić pamięć podręczną.

Valentyn Shybanov
źródło
22

Rozwiązanie dla Firefoksa (33.1.1) za pomocą Firebug (22.0.6)

  1. Narzędzia> Narzędzia internetowe> Firebug> Otwórz Firebug.
  2. W widokach Firebug przejdź do widoku „Net”.
  3. Symbol rozwijanego menu pojawi się obok „Net” (tytuł widoku).
  4. Wybierz „Wyłącz pamięć podręczną przeglądarki” z menu rozwijanego.
hadaytullah
źródło
Próbowałem na Firebug (2.0.11) i Firefox (38.0.1) na Macu, ale to nie działało.
paullb
19

Ten fragment pomógł mi pozbyć się buforowania szablonów

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

Szczegóły następującego fragmentu kodu można znaleźć pod tym linkiem: http://oncodesign.io/2014/02/19/safely-prevent-template-caching-in-angularjs/

Code Prank
źródło
nitpick, ale kiedy prąd nigdy nie jest przedmiotem? Nie jestem pewien, czy go tam nigdy nie ma, aleif (!current) { return; }
Nate-Wilkins
To pokonuje buforowanie przez Angular szablonów opartych na trasach, ale nie częściowe ng-include'd.
bradw2k
16

Zamieszczam to po to, aby omówić wszystkie możliwości, ponieważ żadne inne rozwiązanie nie działało dla mnie (powodowały błędy między innymi z powodu zależności między szablonami angular-bootstrap).

Podczas opracowywania / debugowania określonego szablonu możesz upewnić się, że zawsze się odświeża, dołączając znacznik czasu do ścieżki, jak poniżej:

       $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();
            };
          }
        });

Uwaga końcowy ?nd=' + Date.now()w templateUrlzmiennej.

diosney
źródło
1
Później możesz ustawić, .value('DEBUG', true)aby włączyć tę linię lub nie.
diosney
1
Moje rozwiązanie było użyć następujących w fazie inicjalizacji mojego głównego modułu mocy .run(function($rootScope) { $rootScope.DEBUG = true; ..., a następnie w ramach dyrektywy wstrzyknąć $ rootScope jak .directive('filter', ['$rootScope', function($rootScope)...iw zwrócony obiekt-obiekt: templateUrl: '/app/components/filter/filter-template.html' + ($rootScope.DEBUG ? '?n=' + Date.now() : ''). Może mógłbyś rozwinąć swoje podejście .value („DEBUG”, prawda)? Pozytywne!
JackLeEmmerdeur
Użycie .value('DEBUG', truejest takie samo, jak w przypadku $rootScope, ale bez bałaganu :) Możesz później wstrzyknąć DEBUGdo kontrolera i wysłać zapytanie jako normalną usługę.
diosney,
Czy mógłbyś rozszerzyć kod źródłowy w swojej odpowiedzi, tak aby zawierał to .value(...), co nie jest zbyt skomplikowane? Przypuszczam, że ta koncepcja to najlepsza praktyka kątowa nieznana mi.
JackLeEmmerdeur
1
To rozwiązanie jest bardzo przydatne podczas pracy z Ionic. Zaoszczędzi mi to tyle czasu, że sprawia, że ​​przeładowanie na żywo jest znów przydatne. Wielkie dzięki!
ajuser
11

Jak powiedzieli inni, całkowite pokonanie buforowania dla celów programistycznych można łatwo zrobić bez zmiany kodu: użyj ustawień przeglądarki lub wtyczki. Poza dev, aby pokonać buforowanie szablonów kątowych szablonów opartych na trasach, usuń adres URL szablonu z pamięci podręcznej podczas $ routeChangeStart (lub $ stateChangeStart, dla interfejsu użytkownika routera), jak pokazał Shayan. Nie wpływa to jednak na buforowanie szablonów ładowanych przez ng-include, ponieważ szablony te nie są ładowane przez router.

Chciałem być w stanie naprawić dowolny szablon, w tym te ładowane przez ng-include, w produkcji i umożliwić użytkownikom szybkie otrzymywanie poprawki w przeglądarce bez konieczności ponownego ładowania całej strony. Nie przejmuję się również pokonaniem buforowania HTTP dla szablonów. Rozwiązaniem jest przechwycenie każdego żądania HTTP, które wysyła aplikacja, zignorowanie tych, które nie są dla szablonów .html mojej aplikacji, a następnie dodanie parametru do adresu URL szablonu, który zmienia się co minutę. Pamiętaj, że sprawdzanie ścieżki jest specyficzne dla ścieżki szablonów aplikacji. Aby uzyskać inny interwał, zmień matematykę parametru lub usuń% całkowicie, aby nie buforować.

// 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
źródło
Interesuje mnie twoje rozwiązanie - czy trzymasz ten kod na dobre - czy przez pewien czas po dokonaniu zmiany? Powód - byłby zaniepokojony wydajnością. Wspominasz także, że efekt uboczny pokonuje HTTP. Masz na myśli to, że jest to dobry sposób na efekt uboczny, poprawny - co oznacza, że ​​właśnie to chciałeś, aby uzyskać „poprawkę”? Thx
jamie
1
Zostawiam ten kod na dobre, chociaż cofnęliśmy czas pomijania pamięci podręcznej do 10 minut. Tak więc co 10 minut użytkowania użytkownik będzie ładował nowe szablony HTML. W przypadku mojej aplikacji biz jest to akceptowalny koszt uzyskania możliwości poprawiania szablonów, ale oczywiście wpłynie to zbytnio na wydajność niektórych rodzajów aplikacji. ... Szkoda, że ​​buforowanie HTTP również zostało pokonane, ale nie widzę sposobu na inteligentne pokonanie buforowania szablonów Angular bez pokonania etag itp. Buforowanie szablonów IMO Angular po prostu nie jest wystarczająco konfigurowalne.
bradw2k
1
+1 Miałem ten sam pomysł, ale przechwytuję tylko dla localhost. Możesz zobaczyć moją implementację przechwytywacza tutaj: overengineer.net/…
joshcomley
@ joshcomley Jeśli potrzebujesz tylko pokonać buforowanie na localhost, dlaczego nie użyć wtyczki przeglądarki, która pokonuje wszystkie buforowanie?
bradw2k
@ bradw2k w ten sposób mam pełną kontrolę nad tym, co jest i nie jest buforowane, co może być przydatne w rozwoju. Testuję również we wszystkich przeglądarkach i nie wszystkie przeglądarki mają rozszerzenia, które robią to, czego potrzebuję. Mogę również mieć wskaźnik na stronie w trakcie rozwoju, który mówi mi, czy buforowanie jest wyłączone, ponieważ czasami chcę tylko wyłączyć i przetestować przez przeglądarki na jakiś czas.
joshcomley
8

Jeśli używasz routera interfejsu użytkownika, możesz użyć dekoratora i zaktualizować usługę $ templateFactory oraz dołączyć parametr ciągu zapytania do templateUrl, a przeglądarka zawsze załaduje nowy szablon z serwera.

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]);

Jestem pewien, że możesz osiągnąć ten sam wynik, dekorując metodę „when” w $ routeProvider.

Aman Mahajan
źródło
O wiele lepszą alternatywą jest użycie wtyczki takiej jak gulp-angular-templatecache do zarejestrowania kątowych szablonów js w $ templateCache. Należy tego używać wraz z gulp-rev. Za każdym razem, gdy zmienia się szablon, tworzony jest nowy plik JavaScript z innym numerem wersji i buforowanie nigdy nie będzie problemem.
Aman Mahajan,
3

Odkryłem, że metoda przechwytująca HTTP działa całkiem nieźle i zapewnia dodatkową elastyczność i kontrolę. Dodatkowo możesz pomijać pamięć podręczną dla każdej wersji produkcyjnej, używając skrótu wersji jako zmiennej buster.

Oto jak wygląda metoda buforowania deweloperów przy użyciu 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
źródło
1

Oto kolejna opcja w Chrome.

Hit, F12aby otworzyć narzędzia programistyczne. Następnie Zasoby > Pamięć podręczna > Odśwież pamięć podręczną .

wprowadź opis zdjęcia tutaj

Podoba mi się ta opcja, ponieważ nie muszę wyłączać pamięci podręcznej, jak w przypadku innych odpowiedzi.

Pęto
źródło
W przeglądarce Chrome w wersji 54.0.2840.99 w listopadzie 2016 r. Znalazłem to na karcie o nazwie Aplikacja.
StackOverflowUser
0

Nie ma rozwiązania, które zapobiegałoby buforowaniu przeglądarki / proxy, ponieważ nie można mieć nad tym kontroli.

Innym sposobem na wymuszenie świeżej zawartości dla użytkowników, aby zmienić nazwę pliku HTML! Dokładnie tak jak https://www.npmjs.com/package/grunt-filerev dla zasobów.

Thomas Decaux
źródło