Angular 中数组的异步更新
Async update of array in Angular
我有一个渲染推文的视图。在推文中,有user_mentions数组。从这个数组中,我想获取一个用户,向 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>
内容变量将包含所有推文。最初,content[i].show 对于所有 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(data){
$scope.content[i].thumb = data.avatar;
$scope.content[i].show = true;
});
}
}
现在,我面临的问题是,调用UserAvatar服务后,变量i将继续递增。因此,当到达回调时,我将具有 data.length 的值(因此,将抛出未定义的错误)。我通过将 i 传递给 API 然后将其取回找到了解决方法:
UserAvatar.get(data[i].user_mentions[0].screen_name, i).then(function(data){
$scope.content[i].thumb = data.avatar;
$scope.content[i].show = true;
});
我意识到这只是让它工作的黑客,但是有没有更聪明的方法呢?
每当调用一个函数时,你必须记住,当它被执行时,由外部函数创建的作用域中的所有变量(不仅是$scope
,还有像 i 这样的外部变量)对函数都是可见的,我想你已经意识到了这一点,重要的是要意识到你实际上不需要在.then
的处理程序中i
你需要在索引i
获取内容,但是你如何摆脱这种依赖?我提出两种可能的解决方案:
1)
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]);
}
}
当调用.then
函数的处理程序时,i
依赖项不再存在
2)
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]));
}
}
在此解决方案中,IIFE 返回一个函数,该函数将成为处理程序,但 IIFE 实际上将捕获正在分析的内容的值,因此当返回的内部函数(这是 .then
的onFulfilled
处理程序)被调用时,没有i
依赖关系
奖励:对我处理函数有很大帮助的一条规则如下:
函数将在定义它的位置执行
我不记得我在哪里读到它,我想它是在Nicholas Zakas的Web开发人员专业JavaScript中,强烈推荐:)
我意识到这只是使其工作的黑客,但是有没有 更聪明的方法?
正如@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 (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)
})()
}
问题是你试图在 for 循环中使用闭包,这并不像你发现的那样有效。您的黑客是修复它的一种选择。另一种方法是使用 forEach()
/map()
或 IIFE ( (function(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
});
- 当视图在AngularJS中返回时,我如何获得异步服务调用来更新视图
- Angular js - 异步调用 $scope.users 后不更新模态值
- 网页异步更新的方式有哪些
- 如何使用javascript异步更新我的内容
- Angular 中数组的异步更新
- 处理角控制器中异步更新的正确方法
- 异步更新标签时出现问题
- MVC中模型的异步更新
- 有没有更好的方法可以在不使用setInterval的情况下创建异步更新
- 异步更新EmberJS夹具适配器
- 如何在Javascript中异步更新动态生成的HTML控件
- 异步更新没有AJAX的DIV层
- 在AngularJS的ng-click处理程序中,异步更新模型时忽略第一个更新
- 从Promises异步更新DOM
- 当“喜欢”时,使用ajax异步更新mysql字段;点击
- SharePoint 2010异步更新打破了内联编辑的日期选择器
- 流星:异步更新订阅
- Angular -异步更新&从服务到控制器的呈现
- node.js中没有异步更新的变量
- 如何异步更新页面