目标
我正在尝试创建一系列承诺"增强器",它们将围绕现有的承诺(简单的http请求)添加功能(如缓存,排队,重定向处理等).
问题
我正在通过这种增强承诺的方法遇到的问题是,如果增强功能将任何功能或公共可访问的属性添加到承诺中(或者如果我正在包装已经增强的承诺,例如一个重复的请求),那么当我通过返回一个新的包装它在一个新的承诺$q
.
题
我可以使用什么模式来增强或包装承诺(如下面的两个示例中所示),但不会丢失承诺可能具有的任何其他(非冲突)增强功能?
例1
这是一个自动处理503-Retry-After错误的示例:
function _enhancePromiseWithAutoRetry(promise) { var enhancedPromise = $q(function(resolve, reject) { var newReject = get503Handler(this, resolve, reject); promise.then(resolve, newReject); }); // 503 handling isn't enabled until the user calls this function. enhancedPromise.withAutoRetry = function(onRetry, timeout) { var newPromise = angular.copy(this); newPromise._503handled = true; newPromise._503onRetry = onRetry; newPromise._503timeout = timeout; return newPromise; }; return enhancedPromise; }
我的想法是,如果我返回使用上述功能增强的承诺,用户可以:
someRequest.withAutoRetry().then(onSuccess, onError);
或者更清楚(带链接):
someRequest.then(onSuccess, onAnyError) .withAutoRetry().then(onSuccess, onNon503Error);
这里,then(...)
如果服务器繁忙,第一次调用可能会立即出错,但之后的调用.withAutoRetry()
会在重复请求之前轮询服务器,直到响应成功,或者RetryAfter
返回非错误.
例2
这是另一个添加自定义缓存行为的示例:
function _enhancePromiseWithCache(promise, cacheGet, cachePut) { // Wrap the old promise with a new one that will get called first. return $q(function(resolve, reject) { // Check if the value is cached using the provided function var cachedResponse = cacheGet !== undefined ? cacheGet() : undefined; if(cachedResponse !== undefined){ resolve(cachedResponse); } else { // Evaluate the wrapped promise, cache the result, then return it. promise.then(cachePut); promise.then(resolve, reject); } }); }
这个允许库设置数据缓存,可以使用而不是向服务器发出请求,并且可以在请求完成后添加.例如:
lib.getNameOrigin = function(args) { var restRequest = Restangular.all('people').one(args.id).get('nameOrigin'); // Cache, since all people with the same name will have the same name origin var enhancedPromise = _enhancePromiseWithCache(restRequest, function(){ return nameOrigins[args.name]; }, function(val){ nameOrigins[args.name] = val; }); return enhancedPromise; }
别处
// Will transparently populate the cache lib.getNameOrigin({id: 123, name:'john'}).then(onSuccess, onError).then(...);
而在其他地方完全
// Will transparently retrieve the result from the cache rather than make request lib.getNameOrigin({id: 928, name:'john'}).then(onSuccess, onError);
可能解决方案
我考虑过复制原始的承诺,但是then
用一个引用原始承诺的实现then
(使用代理模式)覆盖新的函数,但是这样安全吗?我知道承诺不仅仅是then
功能.