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。(我想其他Web服务器也存在类似的情况)。
gatoatigrado

4
如果您使用的镀铬只是做了Ctrl+Shift+R(即硬重载)和无论什么缓存机制用于铬会忽视它再取出所有的脚本,样式等
snajahi

4
在Chrome中,ctrl + shift + R不适用于我,但是在开发人员工具的“网络”标签上,单击“禁用缓存”非常有效。对我来说,这是一个客户端问题,不应该像下面的许多建议那样使用服务器上的hack来解决。它应该固定在存在“问题”的客户端上。如果您在服务器上修复它,却忘记取消修复它,则生产可能受到不利影响。
Ant Kutschera 2015年

8
ctrl + shift + R绕过普通请求的缓存。由angular提出的ajax请求ng-include| ng-view| templateUrl通过此快捷方式都没有处理
安德烈Werlang

2
您不能要求所有最终用户在访问站点时都按Ctrl + Shift + R,那么对于非开发案例,该问题的答案是什么?“对我来说,这是一个客户端问题,不应该像下面的许多建议那样使用服务器上的黑客来解决。”-我不同意,您无法在Web环境中控制客户端,因此可以解决生产问题必须由应用程序驱动。因此,我接受了:$ rootScope。$ on('$ viewContentLoaded',function(){$ templateCache.removeAll();});
罗伯特·克里斯蒂安

Answers:


200

对于开发,您还可以停用浏览器缓存-在右下角的Chrome开发者工具中,点击齿轮并勾选选项

禁用缓存(打开DevTools时)

更新:在Firefox中,调试器->设置->高级部分中有相同的选项(已检查版本33)

更新2:尽管此选项显示在Firefox中,但有些报告不起作用。我建议使用萤火虫并遵循hadaytullah的答案。


7
这应该是可以接受的答案,因为它不需要更改代码,而且更符合OP的要求。当然,您可能希望生产应用程序缓存请求,因此,如果代码保留在生产应用程序中,那么上述人员的建议虽然很好,但可能会引起问题。
亚伦·瓦格纳

对其他浏览器(如Firefox)有何建议?
Lereveme 2014年

在Firefox中:调试器>设置(齿轮)有相同的选项。
LukeSolar 2014年

5
这在Firefox中不起作用。即使禁用了缓存并且打开了工具箱,模板仍然被缓存。
Patrick J Collins

4
缓存也会影响生产吗?如果我将新的Web文件推送到服务器该怎么办,这会阻止生产客户端的后续请求加载预发布的缓存版本?
meffect 2015年

111

这是在@Valentyn的答案基础上构建的,这是一种在ng-view内容更改时始终自动清除缓存的方法:

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

@ user252690可能还需要确保html模板未与缓存头一起发送。参见此处此处的可能的解决方法
克里斯·福斯特

30
有点警告:清空$ templateCache可能实际上会带来意想不到的后果。例如,UI Bootstrap在初始化期间将默认部分直接添加到$ templateCache中,然后希望它们在其中。
Strille 2014年

@Strille我试图使用angular-ui-bootstrap Modal。弹出窗口不可见。因为$ templateCache.removeAll(); 有什么解决办法吗?
Mukun 2014年

4
@Mukun:除了不使用removeAll()之外,没有简单的解决方法,而是使用remove()删除需要清除的键。您可能需要进行某种簿记,才能知道要删除哪些键。
Strille 2014年

有什么方法可以清除仅针对特定ui视图缓存的缓存。
加安2015年

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
是的,即使这不能直接回答原始问题,实际上也确实帮助我解决了实时网站上的缓存问题。
2014年

31

如果您正在谈论用于缓存模板而不用于重新加载整个页面的缓存,则可以通过以下方式将其清空:

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

并在标记中:

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

然后按此按钮清除缓存。


22

使用Firebug(22.0.6)的Firefox(33.1.1)解决方案

  1. 工具> Web工具> Firebug>打开Firebug。
  2. 在Firebug视图中,转到“ Net”视图。
  3. 下拉菜单符号将出现在“ Net”(视图标题)旁边。
  4. 从下拉菜单中选择“禁用浏览器缓存”。

在Mac上的Firebug(2.0.11)和Firefox(38.0.1)上进行了尝试,但这不起作用。
paullb 2015年

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-included的parts。
bradw2k 2015年

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变量。


1
以后,您可以设置a .value('DEBUG', true)以启用或禁用该行。
diosney 2015年

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',true)方法?已投票!
JackLeEmmerdeur'5

的用法.value('DEBUG', true与您的用法 相同$rootScope,但不会造成混乱:)您以后可以注入DEBUG控制器并作为常规服务进行查询。
diosney

.value(...)如果不是太复杂,您是否可以将答案中的源代码扩展为包括小东西?我想后面的概念是我所不知道的有角度的最佳实践。
JackLeEmmerdeur'5

1
与Ionic一起使用时,此解决方案非常有用。这将节省我很多时间,因为它使livereload再次有用。万分感谢!
ajuser 2015年

11

正如其他人所说,完全可以轻松实现出于开发目的的缓存,而无需更改代码:使用浏览器设置或插件。在开发人员之外,要击败基于路由的模板的Angular模板缓存,请在Shaft显示的$ routeChangeStart(或对于UI Router为$ stateChangeStart)期间从缓存中删除模板URL。但是,这不会影响ng-include加载的模板的缓存,因为这些模板不是通过路由器加载的。

我希望能够在生产环境中修复任何模板,包括由ng-include加载的模板,并使用户能够在浏览器中快速收到此修复程序,而不必重新加载整个页面。我也不担心打败HTTP缓存模板。解决方案是拦截该应用程序发出的每个HTTP请求,忽略那些不是针对我的应用程序.html模板的HTTP请求,然后向该模板的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 2015年

1
我确实保留了这段代码,尽管我们将缓存清除的时间缩短了10分钟。因此,每使用10分钟,用户将重新加载新的html模板。对于我的biz应用而言,获得热补丁模板的能力是可以接受的成本,但是显然,这将对某些类型的应用造成过多的性能损失。...不幸的是,HTTP缓存也被破坏了,但是我看不到在不破坏etag等的情况下智能地击败Angular模板缓存的方法。IMO Angular模板缓存只是不够可配置。
bradw2k

1
+1我有相同的想法,但我只针对本地主机进行拦截。你可以在这里看到我实施拦截:overengineer.net/...
joshcomley

@joshcomley如果您只需要取消本地主机上的缓存,为什么不使用取消所有缓存的浏览器插件呢?
bradw2k

@ bradw2k这样,我可以完全控制缓存的内容和不缓存的内容,这对开发很有用。我也在所有浏览器中进行测试,并非所有浏览器都具有满足我需要的扩展程序。我还可以在开发中的站点上有一个指示器,告诉我是否禁用了缓存,因为有时我只想禁用并在一段时间内跨浏览器进行测试。
joshcomley

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中的“ when”方法来达到相同的结果。


更好的选择是使用类似gulp-angular-templatecache的插件在$ templateCache中注册有角js模板。这应该与gulp-rev一起使用。每次模板更改时,都会创建一个具有不同修订号的新JavaScript文件,并且缓存永远不会成为问题。
阿曼·马哈詹

3

我发现HTTP拦截器方法工作得很好,并提供了更多的灵活性和控制力。另外,您可以通过使用发行版哈希作为无效变量来为每个生产发行版进行缓存无效化。

这是使用dev的devcachebusting方法的样子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打开开发人员工具。然后,选择资源 > 缓存存储 > 刷新缓存

在此处输入图片说明

我喜欢这个选项,因为我不必像其他答案一样禁用缓存。


在2016年11月的Chrome v 54.0.2840.99中,我在名为Application。而不是Resources的选项卡上找到了它。
StackOverflowUser


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.