在AngularJS服务中缓存promise对象

时间:2013-09-11 15:05:26

标签: javascript angularjs promise angular-promise

我想使用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是一个很好的解决方案吗?

3 个答案:

答案 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时具有完全相同的值(第一次除外)