Javascript 数组的异步更新

Javascript 数组的异步更新,javascript,angularjs,asynchronous,Javascript,Angularjs,Asynchronous,我有一个视图,可以在其中渲染推文。在tweets中,有一个用户_提及数组。从这个数组中,我想获得一个用户,向API发出另一个请求,获得用户的化身,然后渲染它。 视图看起来像: <md-item ng-repeat="item in content"> <div class="md-tile-left" ng-if="item.show"> <img ng-src="{{item.thumb}}" class="face" alt="{{item.nam

我有一个视图,可以在其中渲染推文。在tweets中,有一个用户_提及数组。从这个数组中,我想获得一个用户,向API发出另一个请求,获得用户的化身,然后渲染它。 视图看起来像:

<md-item ng-repeat="item in content">
  <div class="md-tile-left" ng-if="item.show">
     <img ng-src="{{item.thumb}}" class="face" alt="{{item.name}}">
  </div>
  <div class="md-tile-content">
     {{item.text}}
  </div>
</md-item>
for(var i = 0; i < data.length; i++) {
  if(data[i].user_mentions[0]) {
     UserAvatar.get(data[i].user_mentions[0].screen_name).then(function(data){
        $scope.content[i].thumb = data.avatar;
        $scope.content[i].show = true;
     });
  }
}

我意识到这只是一个让它工作的技巧,但是有没有更聪明的方法呢?

问题是,您试图在for循环中使用闭包,但它并不像您发现的那样工作。你的黑客是修复它的一个选择。另一种方法是使用
forEach()
/
map()
或iLife(
(函数(i){…})(i);
)将循环包装到函数中

在您的示例中,我将执行以下操作:

  var promises = data.map(function(item, index) {
     if (item.user_mentions[0]) {
        return UserAvatar.get(item.user_mentions[0].screen_name)
           .then(function(itemData) {
             $scope.content[index].thumb = itemData.avatar;
             $scope.content[index].show = true;
           });
     } else {
        return $q();
     }
  });
  $q.all(promises).then(function() {
     // All complete
  });
我意识到,这只是一个黑客使其工作,但有一个 更聪明的方法

正如@MukeshAgarwal在评论中所说,这并不是真正的黑客行为,因为
UserAvatar.get
是一个异步过程

因此,您必须在异步调用时捕获
i
的值

您使用的方法没有那么糟糕,但另一种方法是使用立即调用的函数:

不起作用

for (var i = 0; i < 10; i++) {

    // do something async
    setTimeout(function() { 
        console.log(i); // <- This will log 10 each time (the value of i at execution)
    }, 1000)

}
for(变量i=0;i<10;i++){
//做一些异步的事情
setTimeout(函数(){

console.log(i);//每当调用函数时,您必须记住,当它被执行时,作用域中的所有变量(不仅是
$scope
,还有像i这样的外部变量)由外部函数创建的内容将对函数可见,我想您已经意识到了这一点,需要意识到的一点是,在
的处理程序中实际上不需要
I
。然后
您需要获取索引
I
中的内容,但如何摆脱这种依赖关系?我提供了两种可能的解决方案:

(一)

在这个解决方案中,IIFE返回一个函数,该函数将作为处理程序,但IIFE实际上将捕获所分析内容的值,因此当返回的内部函数(即
oncompleted
处理程序)被调用时,就没有
i
依赖关系

奖励:以下规则对我处理函数有很大帮助:

  var promises = data.map(function(item, index) {
     if (item.user_mentions[0]) {
        return UserAvatar.get(item.user_mentions[0].screen_name)
           .then(function(itemData) {
             $scope.content[index].thumb = itemData.avatar;
             $scope.content[index].show = true;
           });
     } else {
        return $q();
     }
  });
  $q.all(promises).then(function() {
     // All complete
  });
函数将在其定义的位置执行


我不记得我在哪里读过它,我想它是在Nicholas Zakas'中,强烈推荐的:)

这不是一个黑客行为,因为获取化身是异步过程,所以I值将得到增量。如果对你来说变得困难,你也可以使用异步库you@MukeshAgarwal:谢谢!所以你认为这是可以用于公关的东西生产环境?@Mauricioppe:谢谢!我非常喜欢你提供的第二个解决方案。
for (var i = 0; i < 10; i++) {

    (function() {      
        var j = i;   // <- The value of i is captured in j. j is in a closure
        // do something async
        setTimeout(function() { 
            console.log(j);  // <- This will log 0, then 1, then 2 ... then 9 
        }, 1000)
    })()

}
function getAvatar(name, contentToUpdate) {
  return UserAvatar.get(name)
      .then(function (data) {
        contentToUpdate.thumb = data.avatar;
        contentToUpdate.show = true;
      });
}

for(var i = 0; i < data.length; i++) {
  if(data[i].user_mentions[0]) {
     getAvatar(data[i].user_mentions[0].screen_name, $scope.content[i]);
  }
}
for(var i = 0; i < data.length; i++) {
  if(data[i].user_mentions[0]) {
     UserAvatar.get(data[i].user_mentions[0].screen_name).then((function(content) {
        return function (data) {
          content.thumb = data.avatar;
          content.show = true;
        }
     })($scope.content[i]));
  }
}