我正在尝试从http请求创建一个包含name属性和两个promise的数组:一个作为数组,另一个作为对象。我能够使用这种方法获得我需要的信息,但是我无法访问它以在html的范围内显示它。例如,当我注销数组时,“people”我得到一个对象数组(看起来像:[Object,Object,Object]),我必须展开一堆东西来查看每个对象的实际值,以便“person.skills”真的必须是“person.skills。$$ state.value”。此外,在页面上,{{person.name}}将显示,但其他两个只是空对象,如下所示:{}。那么如何才能访问promises的值,以便我可以使用{{person.skills}}来显示数组?
JS
var getPeople = function() {
var named = $q.defer();
$http.get('/getnames').success(function (response) {
named.resolve(response);
});
return named.promise;
};
getPeople().then(function(namesRes) {
var people = [];
names = namesRes;
names.forEach(function(index){
var name = index;
var count = $q.defer();
var skills = $q.defer();
var urls = '/getskillsbyname/' + name;
var urlc = '/getcountbyname/' + name;
$http.get(urls).success(function (response) {
skills.resolve(response);
});
$http.get(urlc).success(function (response) {
count.resolve(response);
});
people.push({name:name, skills:skills.promise, count:count.promise});
});
return people;
}).then(function(people) {
console.log(people);
$scope.people = people;
});
HTML
<div ng-repeat="person in people">
<p>{{person.name}}</p>
<p>{{person.skills}}</p>
<p>{{person.count}}</p>
</div>
答案 0 :(得分:2)
有效保证链的示例:
function getSomeData(){
var defer = $q.defer();
$http.get(urls).success(function (response) {
defer.resolve(response);
});
return defer.promise;
}
然后您可以访问承诺数据,如:
getSomeData().then(function(data){
console.log(data); // This is the response of the $http request
});
在功能中整理您的请求,它看起来更清晰。
默认情况下,$ http也会返回promise,但我建议创建一个服务/工厂,按照你的要求进行操作,然后你需要推迟。
$http.get(urls).then(function(data){
});
答案 1 :(得分:2)
您的方法未正确返回承诺,您需要使用$q
等待所有内部承诺完成。
我已经通过在forEach
循环中维护大承诺变量来实现您的代码,每当提出skills
和couts
调用时,它都会将该调用放在$q.all
内$q.all
承诺已移至grandPromiseArray
。
var getPeople = function() {
return $http.get('/getnames');
};
getPeople().then(function(response) {
var people = [];
names = response.data;
grandPromiseArray = [];
names.forEach(function(index) {
var name = index, count = $q.defer(), skills = [],
urls = '/getskillsbyname/' + name, urlc = '/getcountbyname/' + name;
grandPromiseArray.push(
$q.all([$http.get(urls), $http.get(urlc)])
.then(function(response) {
people.push({
name: name,
skills: response[0].data, //response[0] value returned by 1st promise
count: response[1].data //response[1] value returned by 2nd promise
});
})
);
});
return $q.all(grandPromiseArray).then(function() {
return people
});
})
.then(function(people) {
console.log(people);
$scope.people = people;
});
答案 2 :(得分:1)
Promise不会自动允许您在Angular中显示结果。
Promise是一个对象,它允许您通过传入最终触发并传递值的函数将异步操作链接在一起。
你不能要求myPromise.value
并期望它在那里,因为它是一个异步过程,可能需要20ms,2分钟,或者可能永远不会回来。
就结构如何构成而言,如果将数据获取部分分解为服务,并将服务注入控制器,则可能更清晰,更容易推理。
我不确定您使用过哪种版本的Angular,但我希望它至少为1.2。 另外,我的例子是使用原生的Promise构造函数,但是如果你没有使用promise polyfill,我肯定Angular的$ q版本现在已经拥有了所需的一切。
function PersonService (http) {
function getResponseData (response) { return response.data; }
function getURL (url) { return http.get(url).then(getResponseData); }
function makePerson (personData) {
return {
name: personData[0],
skills: personData[1],
count: personData[2]
};
}
var personService = {
getNames: function () { return getURL("/names/"); },
getSkills: function (name) { return getURL("/getskillsbyname/" + name); },
getCounts: function (name) { return getURL("/getcountsbyname/" + name); },
loadPerson: function (name) {
return Promise.all([
Promise.resolve(name),
personService.getSkills(name),
personService.getCount(name)
]).then(makePerson);
},
loadPeople: function (names) {
return Promise.all(names.map(personService.loadPerson));
}
};
return personService;
}
这是我个人服务的样子。
我写了几个超小辅助函数,不断重用。
然后我就把这个服务全部用于获取人或有关人的细节
我正在使用Promise.all
,并向其传递一系列承诺。当数组中的每个promise都完成后,它将返回promises返回的所有数据的数组。 Promise.resolve
用于一个地方。它基本上返回一个自动成功的承诺,并给出它的值。这使得它非常有用,当你需要一个承诺来启动一个链,但你不需要做任何特别的事情,除了返回你已经拥有的值。
我的假设是q
现在以与规范相同的方式命名其方法,并且Angular的$q
实现也遵循规范。
function MyController (personService) {
var controller = this;
controller.people = [];
controller.error = false;
init();
function setPeople (people) {
controller.people = people || [];
}
function handleError (err) {
setPeople([]);
controller.error = true;
}
function init () {
return personService.getNames()
.then(personService.loadPeople)
.then(setPeople)
.catch(handleError);
}
}
我的控制器现在变得非常非常简单。它正在使用该服务获取名称,加载人员,然后设置它们,并且它已经准备好了。如果出现错误,我会以任何有意义的方式处理它。
处理这些东西的注入非常简单快捷:
angular.module("myExample")
.service("PersonService", ["$http", PersonService])
.controller("MyController", ["PersonService", MyController]);
在页面上使用此功能现在也很简单:
<div ng-controller="MyController as widget">
<ul ng-hide="widget.people.length == 0">
<li ng-repeat="person in widget.people">
<person-details person="person"></person-details>
</li>
</ul>
<div ng-show="widget.error">Sorry, there was an error with your search.</div>
</div>
答案 3 :(得分:0)
我认为您可以使用$q.all
来构建您的员工:
var p = $q.all({
name: $q.when(name),
skills: $http.get(urls),
count: $http.get(urlc)
});
p.then(function(person) {
people.push(person);
});
$q.all
将构造一个新的promise,当所有输入promise都解析时,它将被解析。由于我们输入了地图,$q.all
将使用具有相同键的地图解析。值是相应承诺的分辨率。在这种情况下,这是一个人,所以我们可以直接将它推入人员阵列。
这是一个稍微天真的实现。由于调用是异步的,因此无法保证名称的顺序将保留在人员中 - 但如果重要的话,您应该很难解决这个问题。
答案 4 :(得分:0)
创建一个包含计数和技能的所有承诺的数组。为了便于阅读,已将这些请求分解为自己的功能
then()
的{{1}}还会返回一个具有属性$http
的承诺对象
data