2015-12-02 34 views
0

我希望两个不同的控制器在服务中解析了一些承诺后运行不同的功能(我不希望此服务每次控制器需要数据时发出http请求,我只想要一个http请求)。承诺在多个控制器中看到的分辨率

我有一个提出请求并获得承诺的服务。我想让controller1看到这个分辨率,然后运行一些代码。然后,我想让controller2也看到这个承诺解决并运行一些代码(基本上是多个then()方法,它们在相同的承诺上运行,但是来自不同的文件)。我怎么能这样做呢?

我看到的所有示例都有一个控制器在某个承诺解决后运行代码,但不是多个控制器正在侦听相同的解决承诺。

这里是从这篇文章中的一些代码IM借款(生病添加一个“母亲控制器”来说明我的例子,我不想让儿子服务,永远做他的HTTP调用两次):http://andyshora.com/promises-angularjs-explained-as-cartoon.html

儿子服务

app.factory('SonService', function ($http, $q) { 
    return { 
     getWeather: function() { 
      // the $http API is based on the deferred/promise APIs exposed by the $q service 
      // so it returns a promise for us by default 
      return $http.get('http://fishing-weather-api.com/sunday/afternoon') 
       .then(function(response) { 
        if (typeof response.data === 'object') { 
         return response.data; 
        } else { 
         // invalid response 
         return $q.reject(response.data); 
        } 

       }, function(response) { 
        // something went wrong 
        return $q.reject(response.data); 
       }); 
     } 
    }; 
}); 

父亲控制器:

// function somewhere in father-controller.js 
     var makePromiseWithSon = function() { 
      // This service's function returns a promise, but we'll deal with that shortly 
      SonService.getWeather() 
       // then() called when son gets back 
       .then(function(data) { 
        // promise fulfilled 
        if (data.forecast==='good') { 
         prepareFishingTrip(); 
        } else { 
         prepareSundayRoastDinner(); 
        } 
       }, function(error) { 
        // promise rejected, could log the error with: console.log('error', error); 
        prepareSundayRoastDinner(); 
       }); 
     }; 

母亲控制器:

var makePromiseWithSon = function() { 
      SonService.getWeather() 
       // then() called when son gets back 
       .then(function(data) { 
        // promise fulfilled 
        if (data.forecast==='good') { 
         workInTheGarden(); 
        } else { 
         sweepTheHouse(); 
        } 
       }, function(error) { 
        // promise rejected, could log the error with: console.log('error', error); 
        sweepTheHouse(); 
       }); 
     }; 
+1

只要它在同样的情况下,你可以做出既控制器中提供的承诺参考,它不应该是太大的问题,然而,这个问题似乎模糊地承担责任? – adeneo

+0

是的,只需创建多个使用服务中相同承诺的控制器即可。它将开箱即用。 – Bergi

+0

@Bergi,你能看看我的编辑吗?你是说我可以让母控制器和太阳服务不会为它做一个额外的http呼叫吗?基本上是一个http请求,每个控制器在解析时都可以使用它。我关心的原因是因为请求正在执行大量查询。 –

回答

1

要让您的工厂服务只获取一次url,请将httpPromise存储在您的工厂服务中。

app.factory('SonService', function ($http) { 
    var weatherPromise; 
    function getWeather() { 
     return $http.get('http://fishing-weather-api.com/sunday/afternoon') 
       .then(function(response) { 
        if (typeof response.data === 'object') { 
         return response.data; 
        } else { 
         // invalid response 
         throw response; 
        } 

       }, function(response) { 
        // something went wrong 
        throw response; 
       }); 
    } 
    function sonService() { 
     if (!weatherPromise) { 
     //save the httpPromise 
     weatherPromise = getWeather(); 
     } 
     return weatherPromise; 
    } 
    return sonService; 
}); 
1

答案很简单,在非角特异性(但很容易应用到角)的方式,是创建缓存ON-出站请求(而非缓存返回值,最喜欢的服务系统会)。

function SearchService (fetch) { 
    var cache = { }; 
    return { 
    getSpecificThing: function (uri) { 
     var cachedSearch = cache[uri]; 
     if (!cachedSearch) { 
     cachedSearch = fetch(uri).then(prepareData); 
     cache[uri] = cachedSearch; 
     } 
     return cachedSearch; 
    } 
    }; 
} 


function A (searchService) { 
    var a = this; 
    Object.assign(a, { 
    load: function () { 
     searchService.getSpecificThing("/abc").then(a.init.bind(a)); 
    }, 
    init: function (data) { /* ... */ } 
    }); 
} 

function B (searchService) { 
    var b = this; 
    Object.assign(b, { 
    load: function () { 
     searchService.getSpecificThing("/abc").then(b.init.bind(b)); 
    }, 
    init: function (data) { /* ... */ } 
    }); 
} 


var searchService = SearchService(fetch); 
var a = new A(searchService); 
var b = new B(searchService); 

a.load().then(/* is initialized */); 
b.load().then(/* is initialized */); 

他们共享相同的承诺,因为服务都不约而同地缓存和返回同样的承诺。

如果您想要安全,可以缓存承诺,然后根据缓存的承诺返回解析(或拒绝)的承诺的新实例。

// instead of 
return cachedSearch; 

// replace it with 
return Promise.resolve(cachedSearch); 

现在每个用户是得到一个新的实例,每次你犯了一个请求,但每个实例也传递或在原有基础上缓存调用失败。
当然,你可以进一步,并在缓存上放置一个时间限制,或者使用挂钩使缓存无效,或者其他任何...

此转换成角也是易如反掌

  • SearchService是服务
  • AB是控制器
  • 使用$http代替fetch(虽然取是真的很漂亮)在​​
  • 你会成功从JSON转换数据;
    $http,你会回来response.data,因为用户不希望有这样做
    无论哪种方式,你执行该操作的只有一次,每呼出呼叫,所以缓存它,太
  • 使用$q(和q方法),而不是本地Promise
  • 使用angular.extend,而不是Object.assign
  • 大功告成的;现在你已经移植是整个概念到棱角和VanillaJS