【问题标题】:Caching a promise object in AngularJS service在 AngularJS 服务中缓存一个承诺对象
【发布时间】: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 - 你是对的。这没有意义。事实上,它什么也没做。 (但它也不会破坏任何东西,因为没有使用链)

标签: javascript angularjs promise angular-promise


【解决方案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都被解析了。在某些情况下,这是一个很大的优势
      • 你最终为我节省了很多冗余和错误的代码
      猜你喜欢
      • 1970-01-01
      • 2014-11-20
      • 1970-01-01
      • 2014-04-29
      • 2015-04-08
      • 2023-03-03
      • 1970-01-01
      相关资源
      最近更新 更多