$resource 的自定义缓存
Custom caching for $resource
我的 AngularJS 中有以下模式需要重构:
$scope.advertisers = Advertiser.query()
$scope.advertisersMap = {};
$scope.advertiser.$then(function (response) {
arrayToMap(response.resource, $scope.advertisersMap)
}
arrayToMap
是将数组中的每个项目添加到以其 ID 作为键的对象的函数。
现在,我希望这会发生在 Advertiser
本身,例如
$scope.allAdvertisers = Advertiser.query()
// Somewhere else
var advertiser = Advertiser.get({id: 2})
其中 Advertiser.get({id: 2})
将 return 来自查询方法先前填充的缓存。
Advertiser
在工厂中定义:
.factory('Advertiser', ['djResource', 'Group', function ($djResource, Group) {
var Advertiser = $djResource('/campaigns/advertisers/:advertiserId/', {advertiserId: '@id'});
Advertiser.prototype.getGroups = function () {
return Group.getByAdvertiser({advertiserId: this.id});
};
return Advertiser;
}])
遗憾的是,DjangoRestResource(以及它包装的 $resource)通过 URL 进行缓存,因此 query()
将缓存 /advertisers/ 而 get(2)
将缓存 /advertisers/2/,但我希望 query
以 get
也能够检索它的方式进行缓存。
我已经尝试用执行缓存的包装函数替换 query
函数,但我希望它成为 return 一个 promise,它也是一个像 $resource 一样的数组。它是这样的:
var oldQuery = Advertiser.query;
var cache = $cacheFactory('advertisers');
Advertiser.query = function () {
var promise = oldQuery();
return promise.then(function (response) {
angular.forEach(response.resource, function (resource) {
cache.put(resource.id, resource)
})
})
};
但是 returned promise 不再是类似数组的对象,并且它不会像以前那样将 returned 结果封装在 Advertiser 对象中,这会中断我的大部分代码都希望 Advertiser.query()
最终成为一个数组。
我还应该尝试哪些其他方法?这个片段在多个工厂的每个控制器中重复出现,它伤害了我的眼睛。
我不知道 $resource 直接支持任何缓存,您可以创建一个工厂来抽象广告商资源并自己处理缓存。
这里有一些关于缓存的有用信息:
https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#validating-cached-responses-with-etags
我正在使用 $resource 开发一个应用程序,每个方法都是抽象的,所以我可以检查缓存以查看我请求的内容是否存在,return 如果没有,使用 $resource.
拨打电话
问题的解决方法如下:
function makeCachingMethod(object, method, cache, config) {
var $q = angular.injector(['services']).get('$q');
var oldMethod = object[method];
object[method] = function () {
var result;
if (!config.isArray) {
var id = config.idParam ? arguments[0][config.idParam] : arguments[0];
result = cache.get(id);
if (result !== undefined) {
if (result.$promise === undefined) {
result.$promise = $q.when(result);
result.$resolved = true;
}
return result;
}
}
result = oldMethod.apply(this, arguments);
result.$promise.then(function (data) {
if (config.isArray) {
angular.forEach(data, function (item) {
cache.put(item.id, item);
})
} else {
cache.put(data.id, data);
}
return data;
});
return result;
}
}
以及用法示例:
app.factory('Country', ['$resource', '$cacheFactory', function ($resource, $cacheFactory) {
var Country = $resource('/campaigns/countries/:id', {id: "@id"}, {
query: {method: 'GET', url: '/campaigns/countries/', isArray: true},
get: {method: 'GET', url: '/campaigns/countries/:id/', isArray: false}
});
var cache = $cacheFactory('countries');
makeCachingMethod(Country, 'query', cache, {isArray: true});
makeCachingMethod(Country, 'get', cache, {idParam: 'id'});
return Country;
}])
这里发生了什么?
我用makeCachingMethod
装饰了$resource
创建的原始方法。按照 $resource
本身使用的模式,我使用一个配置对象来指示装饰方法 return 是否是一个数组,以及如何在查询中传递 id。不过,我假设要保存的 ID 的密钥是 'id',这对我的模型来说是正确的,但可能需要更改。
注意到在 return 从缓存中获取对象之前,装饰器向其添加了 $promise
和 $resolved
属性,因为我的应用程序期望对象来自 $resource
具有这些属性,并且为了继续使用承诺 API,例如:
$scope.advertiser = Advertiser.get({advertiserId: $scope.advertiserId});
$scope.advertiser.$promise.then(function () {
$scope.doSomething();
});
请注意,由于该函数是在任何 Angular 模块的范围之外定义的,因此需要使用 angular.injector()
注入 $q
服务。更好的解决方案是 return 调用装饰函数的服务。这种服务还可以处理缓存本身的生成。
此解决方案不处理缓存模型的过期问题,这在我的场景中不是什么大问题,因为它们很少改变。
我的 AngularJS 中有以下模式需要重构:
$scope.advertisers = Advertiser.query()
$scope.advertisersMap = {};
$scope.advertiser.$then(function (response) {
arrayToMap(response.resource, $scope.advertisersMap)
}
arrayToMap
是将数组中的每个项目添加到以其 ID 作为键的对象的函数。
现在,我希望这会发生在 Advertiser
本身,例如
$scope.allAdvertisers = Advertiser.query()
// Somewhere else
var advertiser = Advertiser.get({id: 2})
其中 Advertiser.get({id: 2})
将 return 来自查询方法先前填充的缓存。
Advertiser
在工厂中定义:
.factory('Advertiser', ['djResource', 'Group', function ($djResource, Group) {
var Advertiser = $djResource('/campaigns/advertisers/:advertiserId/', {advertiserId: '@id'});
Advertiser.prototype.getGroups = function () {
return Group.getByAdvertiser({advertiserId: this.id});
};
return Advertiser;
}])
遗憾的是,DjangoRestResource(以及它包装的 $resource)通过 URL 进行缓存,因此 query()
将缓存 /advertisers/ 而 get(2)
将缓存 /advertisers/2/,但我希望 query
以 get
也能够检索它的方式进行缓存。
我已经尝试用执行缓存的包装函数替换 query
函数,但我希望它成为 return 一个 promise,它也是一个像 $resource 一样的数组。它是这样的:
var oldQuery = Advertiser.query;
var cache = $cacheFactory('advertisers');
Advertiser.query = function () {
var promise = oldQuery();
return promise.then(function (response) {
angular.forEach(response.resource, function (resource) {
cache.put(resource.id, resource)
})
})
};
但是 returned promise 不再是类似数组的对象,并且它不会像以前那样将 returned 结果封装在 Advertiser 对象中,这会中断我的大部分代码都希望 Advertiser.query()
最终成为一个数组。
我还应该尝试哪些其他方法?这个片段在多个工厂的每个控制器中重复出现,它伤害了我的眼睛。
我不知道 $resource 直接支持任何缓存,您可以创建一个工厂来抽象广告商资源并自己处理缓存。
这里有一些关于缓存的有用信息: https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#validating-cached-responses-with-etags
我正在使用 $resource 开发一个应用程序,每个方法都是抽象的,所以我可以检查缓存以查看我请求的内容是否存在,return 如果没有,使用 $resource.
拨打电话问题的解决方法如下:
function makeCachingMethod(object, method, cache, config) {
var $q = angular.injector(['services']).get('$q');
var oldMethod = object[method];
object[method] = function () {
var result;
if (!config.isArray) {
var id = config.idParam ? arguments[0][config.idParam] : arguments[0];
result = cache.get(id);
if (result !== undefined) {
if (result.$promise === undefined) {
result.$promise = $q.when(result);
result.$resolved = true;
}
return result;
}
}
result = oldMethod.apply(this, arguments);
result.$promise.then(function (data) {
if (config.isArray) {
angular.forEach(data, function (item) {
cache.put(item.id, item);
})
} else {
cache.put(data.id, data);
}
return data;
});
return result;
}
}
以及用法示例:
app.factory('Country', ['$resource', '$cacheFactory', function ($resource, $cacheFactory) {
var Country = $resource('/campaigns/countries/:id', {id: "@id"}, {
query: {method: 'GET', url: '/campaigns/countries/', isArray: true},
get: {method: 'GET', url: '/campaigns/countries/:id/', isArray: false}
});
var cache = $cacheFactory('countries');
makeCachingMethod(Country, 'query', cache, {isArray: true});
makeCachingMethod(Country, 'get', cache, {idParam: 'id'});
return Country;
}])
这里发生了什么?
我用makeCachingMethod
装饰了$resource
创建的原始方法。按照 $resource
本身使用的模式,我使用一个配置对象来指示装饰方法 return 是否是一个数组,以及如何在查询中传递 id。不过,我假设要保存的 ID 的密钥是 'id',这对我的模型来说是正确的,但可能需要更改。
注意到在 return 从缓存中获取对象之前,装饰器向其添加了 $promise
和 $resolved
属性,因为我的应用程序期望对象来自 $resource
具有这些属性,并且为了继续使用承诺 API,例如:
$scope.advertiser = Advertiser.get({advertiserId: $scope.advertiserId});
$scope.advertiser.$promise.then(function () {
$scope.doSomething();
});
请注意,由于该函数是在任何 Angular 模块的范围之外定义的,因此需要使用 angular.injector()
注入 $q
服务。更好的解决方案是 return 调用装饰函数的服务。这种服务还可以处理缓存本身的生成。
此解决方案不处理缓存模型的过期问题,这在我的场景中不是什么大问题,因为它们很少改变。