访问数组中的promises值

时间:2016-02-22 20:13:34

标签: javascript angularjs

我正在尝试从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>

5 个答案:

答案 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循环中维护大承诺变量来实现您的代码,每当提出skillscouts调用时,它都会将该调用放在$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