我希望在一个服务中解决一些承诺后,两个不同的控制器运行不同的功能(我不希望这个服务每次控制器需要数据时都发出http请求,我只想要一个http请求)。
我有一个服务可以提出请求并得到承诺。我希望controller1看到这个解决方案,然后运行一些代码。然后,我希望controller2也能看到这个promise解析并运行一些代码(基本上是在同一个promise上运行但来自不同文件的多个then()方法)。我该怎么做?
我看到的所有例子都有一个控制器在某个promise解析后运行代码,但没有多个控制器在侦听同一个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();
});
};
要让您的工厂服务只获取一次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;
});
简单的答案是,以一种非角度特定的方式(但很容易应用于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 */);
他们共享相同的承诺,因为与他们交谈的服务缓存并返回了相同的承诺。
如果您希望安全,可以缓存一个promise,然后返回基于缓存的promise解析(或拒绝)的promise的新实例。
// instead of
return cachedSearch;
// replace it with
return Promise.resolve(cachedSearch);
现在,每次发出请求时,每个用户都会获得一个新实例,但每个实例也会根据原始缓存调用通过或失败
当然,你可以更进一步,对缓存设置时间限制,或者使用钩子使缓存无效,或者其他什么。。。
将其转换为Angular也是一个快速
SearchService
是一项服务A
和B
是控制器- 使用
$http
而不是fetch
(尽管fetch非常漂亮) - 在
fetch( ).then(prepareData)
中,您将在成功时从JSON转换数据
在$http
中,您将返回response.data
,因为您的用户不希望这样做
无论哪种方式,每次出站调用都只执行一次该操作,所以也要缓存它 - 使用
$q
(和q
方法)而不是本机Promise
- 使用
angular.extend
,而不是Object.assign
- 你完了;您现在已经将整个概念移植到Angular AND VanillaJS中