我想使用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是一个很好的解决方案吗?
答案 0 :(得分:47)
这是正确的方法吗?
是。在返回的函数上使用memoisation可以避免重复执行异步(通常是昂贵的)任务的常用技术。承诺使缓存变得容易,因为人们不需要区分正在进行的操作和已完成的操作,它们都表示为(相同的)结果值的承诺。
这是正确的解决方案吗?
没有。全局data
变量和undefined
的分辨率不是承诺的工作方式。相反,用结果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。
答案 1 :(得分:3)
对于此任务,我创建了名为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;
}
否则你将对后端进行重复调用。
答案 2 :(得分:0)
此设计设计模式将缓存第一次运行时返回的内容,并在每次再次调用时返回 cached 。
async function doLogin() {
try {
const name = await Login.findOne()
printName(name)
} catch(e) {
console.error(e)
}
}
用另一个返回函数的自调用函数(您原始的异步函数)简单地包装您的函数,包装函数的目的是为局部变量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
时具有完全相同的值(第一次除外)