承诺在多个控制器中看到分辨率

时间:2015-12-02 21:12:48

标签: javascript angularjs q angular-promise angular-resource

我希望两个不同的控制器在服务中解决一些promise之后运行不同的函数(我不希望每次控制器需要数据时这个服务都发出一个http请求,我只想要一个http请求。)

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

我看到的所有示例都有一个控制器在某个承诺解析后运行代码,但没有多个控制器监听同一个承诺解析。

这里是我从这篇文章借用的一些代码(生病添加一个'母亲控制器'来说明我的例子,我不希望儿子服务能够两次进行他的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();
                });
        };

2 个答案:

答案 0 :(得分:1)

要让您的工厂服务仅获取网址,请将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 :(得分:1)

简单的答案,在非角度特定的(但很容易应用于Angular)方式,是创建一个缓存ON-OUTBOUND-REQUEST的服务(而不是像大多数系统那样缓存返回值)。

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);

每次发出请求时,每个用户都会获得一个新实例,但每个实例也会根据原始缓存调用传递或失败。
当然,你可以更进一步,并在缓存上设置一个时间限制,或者使缓存无效,或者等等......

将其转换为Angular也是一个快照

  • SearchService是一项服务
  • AB是控制器
  • 使用$http代替fetch(虽然fetch非常漂亮)
  • fetch( ).then(prepareData)中您成功转换JSON数据;
    $http,您将返回response.data,因为您的用户不想这样做 无论哪种方式,您每次出站呼叫都只执行一次该操作,因此也将其缓存
  • 使用$q(和q方法)代替原生Promise
  • 使用angular.extend,而不是Object.assign
  • 你已经完成了;您现在将整个概念移植到Angular和VanillaJS