如何在角度循环中使用异步调用?

时间:2014-03-26 13:36:41

标签: angularjs asynchronous callback

列表中的每封电子邮件都将发送到服务器,并且如果它是有效的电子邮件,则可以从服务器获取响应。

所以在检查完所有电子邮件后,阵列应该有:

joe@gmail.com - valid
abc@fjkdsl.com - invalid
xyz@yahoo.com - valid
test@nknk.com - invalid

在循环中将电子邮件发送到服务器的代码如下:

for(var i=0; i < isEmailValidList.length; i++) {
  var isEmailValid = User.validateEmail({email : isEmailValidList[i].email}, function(){
      isEmailValidList[i].isValid = isEmailValid.value;
  });
}

但问题是调用是异步的,所以对于说i = 0,当我为0时控件不会进入函数内部。所以当它进入函数值时我可以是任何东西,主要是它大于数组的长度,因此isEmailValidList [i]未定义。如果调用是同步的,那么它将等待响应,我不会增加,但事实并非如此。

那么,如何为其相应的电子邮件获取正确的isValid响应?

2 个答案:

答案 0 :(得分:5)

使用承诺。 Angular可以在没有任何&#34;特殊干预的情况下使用promises,就像为范围变量赋值一样,请参阅plnkr。承诺是&#34;基地&#34;驯服异步编程以便像同步编程一样工作(虽然我们在浏览器中没有javascript生成器)并且受到Angular团队的鼓励,因为它具有高度可测性和可维护性

http://plnkr.co/edit/8BBS2a1kC24BHBWRYp9W?p=preview

// trying to emulate your service here

var app = angular.module('app', []);

app.factory('User', function($q, $timeout){
  User = {};

  User.validateEmail = function(email){
    var d = $q.defer();

    $timeout(function(){
      if (/(yahoo|gmail)/.test(email.email)){
        d.resolve(email); // return the original object, so you can access it's other properties, you could also modify the "email" object to have isValid = true, then resolve it
      } else {
        d.resolve(); // resolve it with an empty result
      }
    }, 1000, false);

    return d.promise;
  };

  return User;
  });

app.controller('MainCtrl', function(User, $q){
  this.emails = [
    {email: 'joe@gmail.com', name: 'Joe'},
    {email: 'abc@fjkdsl.com', name: 'Abc'},
    {email: 'xyz@yahoo.com', name: 'XYZ'}, 
    {email: 'test@nknk.com', name: 'test'}
  ];

  this.isEmailValidList = [];
  var promises = [];

  for(var i=0; i < this.emails.length; i++) {
    promises.push(
      User.validateEmail(this.emails[i]) 
    );
  }

  $q.all(promises).then(function(emails){ 
    this.isEmailValidList = emails.filter(function(e){ return e; });
  }.bind(this));

});

注意:$timeout是模拟异步任务,如数据库调用等。您可以将整个电子邮件数组传递给验证服务,然后返回数组,而不是创建一个中间数组的promises。使用angular,您可以将范围变量分配给承诺,并且可以在ng-repeat上使用它而无需对代码进行任何更改

答案 1 :(得分:3)

您可以使用闭包功能:

for (var i=0; i < isEmailValidList.length; i++) {
  var isEmailValid = User.validateEmail({
     email : isEmailValidList[i].email
  }, (function(i) {
     return function() {
         isEmailValidList[i].isValid = isEmailValid.value;
     };
  })(i));
}