2014-09-27 22 views
1

我想建立一个服务或工厂,允许我通过一些API调用加载日期。 大部分数据都需要重新使用,所以基本上我只想进行一次API调用,下一次我需要这些数据时,它应该只是返回它。Angular.js服务/工厂与可重复使用的数据

现在每当我进行API调用,并且在完成之前,我都会进行相同的调用,我希望第二个调用等待,直到第一个调用完成。

本质上讲,当我这样做:

dataService.getMenu() // Make API call 
dataService.getMenu() // Wait for the first API call to be completed and return that data 

// Somewhere else 
dataService.getMenu() // Return data as API call was already made 

我厂是这样的:

(function() { 
    var app = angular.module('dataService', []); 
    app.factory('dataService', ['$http', '$q', function($http, $q) { 
     var links = [], 
      jobs = []; 

     return { 
      getMenu: function() { 
       var deferred = $q.defer(); 

       console.log(links); 

       if(links.length > 0) { 
        deferred.resolve(links); 
       } else { 
        $http.get('../server/api.php?ajax=true&action=getCats').success(function(data) { 
         links = data; 

         deferred.resolve(data); 
        }) 
       } 

       return deferred.promise; 
      } 
     } 
    }]) 
})(); 

回答

2

只是移动的使用getMenu功能外延迟报关,进厂

app.factory('dataService', ['$http', '$q', function($http, $q) { 
     var links = [], 
      jobs = [], 
      deferredMenu = $q.defer(); 

现在在你的getMenu调用中使用deferredMenu承诺。

getMenu: function() { 
       if(links.length > 0) { 
        deferredMenu.resolve(links); 
       } else { 
        $http.get('../server/api.php?ajax=true&action=getCats').success(function(data) { 
         links = data; 

         deferredMenu.resolve(data); 
        }) 
       } 

       return deferredMenu.promise; 
} 
+0

我的想法是太多,但如果我叫'getMenu'快两倍,它会执行一个'$ http.get()'2次,是否只需要添加一个额外的变量来查看是否已经创建了通话? – 2014-09-27 05:24:28

+0

我可能已经解释了自己的错误,基本上在加载'$ http.get()'时会有几秒钟的时间,无论何时在此期间调用'getMenu()',我都不想进行相同的调用再次。 – 2014-09-27 05:26:37

+0

是的,这种方法第二个电话不会去。记住函数总是返回相同的延迟对象。对函数的第一次调用会创建延迟对象,所有其他对象都会得到相同的延迟。 – Chandermani 2014-09-27 07:33:54

0

您可以在$http服务使用cache配置的为你做到这一点。由于$http caching文档中指出:

要启用缓存,请求配置缓存属性设置为 真(使用默认缓存),或自定义缓存对象( $ cacheFactory建)。启用缓存时,$ http将来自服务器的响应 存储在指定的缓存中。 相同的请求 由下一次,响应从缓存提供,而不发送 请求到服务器

请注意,即使响应从缓存提供,交货 的数据以与实际请求相同的方式异步。

如果是,应该是 使用相同的缓存中的同一个URL多个GET请求,但缓存未填充的是,只有 一个请求到服务器将被制成,剩余的请求将 使用来自第一请求的响应来满足

以上声明符合您的问题中陈述的要求。此外,我省略了$q服务,因为$http方法已经提供了您需要的承诺,您只需使用then()$q服务方法在您的响应中拥有数据对象。

(function() { 
    var app = angular.module('dataService', []); 
    app.factory('dataService', ['$http', function($http) { 
     return { 
      getMenu: function() { 
       return $http.get('../server/api.php?ajax=true&action=getCats', {cache: true}) 
        .then(function(response) { 
        return response.data; 
        }); 
      } 
     }; 
    }]) 
})(); 
+0

谢谢,我之前看过缓存中的构建,之所以我没有这样做,是因为我可能需要修改返回数据,我希望将这个逻辑保留在我的服务中。 – 2014-09-27 07:36:03

+0

您仍然可以修改'.then()'方法中的数据。 – ryeballar 2014-09-27 07:37:05

0

我知道我有点晚回答这个问题,但我面临同样的问题,经过大量研究后提出了一个解决方案。

达到上述要求的方法是使用呼叫排队

以下是相同的步骤:

  1. 对于每个调用,创建一个承诺,承诺加入到队列中。每次呼叫返回defer.promise
  2. 对于队列中的第一项,调用一个函数,它将带上您的api并在API响应中设置一个参数,如IsDataPresent = true(最初为false)。
  3. 解决第一个调用的承诺并将接收到的数据设置为局部变量。执行队列中下一个呼叫的功能,但首先检查IsDataPresent=== true,如果为true,则使用局部变量的数据解析下一个呼叫的承诺。

请参见下面的代码是一样的:

app.factory('dataService', ['$http', '$q', function($http, $q) { 
    var links = '', 
     jobs = [], 
     isDataAlreadyPresent = false; 

    var getMenuCall = function() { 
     var call = jobs[0]; // Retrieve first promise from the queue 
     if (isDataAlreadyPresent) { // This will be false for first call and true for all other 
      call.defer.resolve(links); 
     } else { 
      $http.get('../server/api.php?ajax=true&action=getCats').success(function(data) { //Get API data 
       isDataAlreadyPresent = true; //Set parameter to true 
       links = data; // Set local variable to received data 
       call.defer.resolve.resolve(data); // Resolve the first promise 
       jobs.shift(); // Remove first item from the queue 
       if (jobs.length > 0) { 
        getMenuCall(); // Execute the function for next call's promise in the queue. This time isDataAlreadyPresent== true will be true so it's promise will be resolved by the links data thus avoiding extra call. 
       } 
      }); 
     } 

     return deferredMenu.promise; 
    }; 

    return { 
     getMenu: function() { 
      var defer = $q.defer(); // Create promise for the call 
      jobs.push({ 
       defer: defer // Push each call's promise to the queue 
      }); 
      if (jobs.length === 1) { // For the first call make call above function which will make API call 
       getMenuCall(); 
      } 
      return defer.promise; // Defer promise for the time being 
     } 
    } 
}]); 
相关问题