在 AngularJS 服务中缓存一个承诺对象
Posted
技术标签:
【中文标题】在 AngularJS 服务中缓存一个承诺对象【英文标题】:Caching a promise object in AngularJS service 【发布时间】:2013-09-15 16:37:21 【问题描述】:我想使用 Promises 在 AngularJS 中实现静态资源的动态加载。问题:我在页面上有几个组件可能(或不,取决于显示的,因此是动态的)需要从服务器获取静态资源。加载后,可以在整个应用程序生命周期内进行缓存。
我已经实现了这个机制,但是我是 Angular 和 Promises 的新手,我想确定这是否是一个正确的解决方案\方法。
var data = null;
var deferredLoadData = null;
function loadDataPromise()
if (deferredLoadData !== null)
return deferredLoadData.promise;
deferredLoadData = $q.defer();
$http.get("data.json").then(function (res)
data = res.data;
return deferredLoadData.resolve();
, function (res)
return deferredLoadData.reject();
);
return deferredLoadData.promise;
因此,只发出了一个请求,接下来对 loadDataPromise() 的所有调用都会取回第一个做出的承诺。它似乎适用于正在进行中或前一段时间已经完成的请求。
但是缓存 Promises 是不是一个好的解决方案?
【问题讨论】:
此行不正确:return deferredLoadData.resolve();
。您应该只是 deferredLoadData.resolve();
和 deferredLoadData.reject();
。 return
语句使整个承诺返回 undefined
。
@arcol - 你是对的。这没有意义。事实上,它什么也没做。 (但它也不会破坏任何东西,因为没有使用链)
【参考方案1】:
这种设计模式将缓存第一次运行时返回的内容,并在每次再次调用时返回缓存内容。
const asyncTask = (cache =>
return function()
// when called first time, put the promise in the "cache" variable
if( !cache )
cache = new Promise(function(resolve, reject)
setTimeout(() =>
resolve('foo');
, 2000);
);
return cache;
)();
asyncTask().then(console.log);
asyncTask().then(console.log);
解释:
简单地用另一个返回函数的自调用函数(你原来的异步函数)包装你的函数,包装函数的目的是为局部变量cache
提供封装范围,以便局部变量只能访问在包装函数的返回函数中,并且每次调用 asyncTask
时具有完全相同的值(第一次除外)
【讨论】:
【参考方案2】:对于这个任务,我创建了名为 defer-cache-service 的服务,它删除了所有这些样板代码。它是用 Typescript 编写的,但你可以获取编译后的 js 文件。 Github source code.
例子:
function loadCached()
return deferCacheService.getDeferred('cacke.key1', function ()
return $http.get("data.json");
);
消费
loadCached().then(function(data)
//...
);
需要注意的重要一点是,如果假设两个或多个部分同时调用相同的 loadDataPromise,则必须添加此检查
if (defer && defer.promise.$$state.status === 0)
return defer.promise;
否则您将重复调用后端。
【讨论】:
【参考方案3】:这是正确的方法吗?
是的。在返回的函数上使用memoisation 保证了一种通用技术,可以避免重复执行异步(通常是昂贵的)任务。 Promise 使缓存变得容易,因为不需要区分正在进行的操作和已完成的操作,它们都表示为(相同的)结果值的 Promise。
这是正确的解决方案吗?
没有。全局data
变量和undefined
的分辨率并不是promise 的预期工作方式。相反,用结果data
来履行承诺!它还使编码变得更加容易:
var dataPromise = null;
function getData()
if (dataPromise == null)
dataPromise = $http.get("data.json").then(function (res)
return res.data;
);
return dataPromise;
那么,不是loadDataPromise().then(function() /* use global */ data )
,而是简单的getData().then(function(data) … )
。
为了进一步改进该模式,您可能希望在闭包范围内隐藏dataPromise
,并注意当getData
采用参数(如url)时,您需要查找不同的promise。
【讨论】:
为什么不使用 $cacheFactory?这不是更灵活地从整个模块访问缓存吗? @Darryl:抱歉,我对 Angular 了解不多,我的回答仅基于 Promise。 @Darryl:我想主要的区别是通过使用 $cacheFactory 缓存服务调用的结果,通过“dataPromise”缓存承诺本身。第二种方式,如果你调用了两次服务,第一次调用还没有返回,第二次调用不会被触发,当第一次调用返回时,两个promise都被解析了。在某些情况下,这是一个很大的优势 你最终为我节省了很多冗余和错误的代码以上是关于在 AngularJS 服务中缓存一个承诺对象的主要内容,如果未能解决你的问题,请参考以下文章