Angular中ngFor循环内getUserProfileImage()重复触发如何解决?
问题根因
你现在的写法本身就不符合Angular的最佳实践,会触发死循环完全是意料之中的:
- Angular变更检测每次运行时,都会重新执行模板中绑定的所有方法,你直接把
getUserProfileImage绑到了[src]属性上,任何触发变更检测的行为(页面交互、异步回调、定时器等)都会让这个方法被反复调用。 - 你的
getUserProfileImage方法没有返回值,[src]一开始拿到的是undefined,你在异步回调里手动操作DOM修改图片src,这个DOM修改行为又会反过来触发变更检测,再次调用方法发请求,就形成了死循环。
解决方案
1. 预加载头像地址,模板直接绑定数据属性
不要在模板绑定里调用带异步请求的方法,拿到联系人列表后直接预加载所有头像,把地址存在用户对象的属性里,模板直接绑定这个属性即可,完全不需要手动操作DOM。
组件TS代码示例:
// 假设这是你获取联系人列表的方法 fetchContactList() { this.yourService.getContactList().subscribe(res => { this.listOfContacts = res; // 遍历所有用户预加载头像 this.listOfContacts.forEach(user => { this.util.getUserProfileImageByUserName(user.UserName).subscribe(contactsObj => { // 把头像地址直接挂到用户对象上 user.avatarUrl = this.toUrl(contactsObj["Images"][0].SrcAttr); }) }) }) }
模板代码修改为:
<div *ngFor="let user of listOfContacts"> <img class="rounded profile-thumbnail ptr" <!-- 可以加一个默认占位图做兜底 --> [src]="user.avatarUrl || './assets/default-avatar.png'" [routerLink]="['/community/userProfile', '0', user.UserId]"> </div>
2. 增加头像请求缓存(可选优化)
如果同一个用户可能在列表中多次出现,或者页面会反复刷新列表,可以加一层缓存避免重复发请求:
// 组件内声明缓存Map,存储已请求过的用户名对应的头像地址 private avatarCache: Map<string, string> = new Map(); // 封装获取头像的公共方法 private loadAvatarForUser(user: any): void { // 已有缓存直接赋值 if (this.avatarCache.has(user.UserName)) { user.avatarUrl = this.avatarCache.get(user.UserName); return; } // 无缓存发起请求 this.util.getUserProfileImageByUserName(user.UserName).subscribe(contactsObj => { const avatarUrl = this.toUrl(contactsObj["Images"][0].SrcAttr); this.avatarCache.set(user.UserName, avatarUrl); user.avatarUrl = avatarUrl; }) }
拿到列表后调用这个方法加载头像即可。
以上方案完全不需要修改变更检测策略,也没有hack操作,符合Angular的常规开发规范。
内容的提问来源于stack exchange,提问作者Amir Dora.
相关产品推荐
相关产品推荐

