Angular中customerTasks数组显示3个元素但仅能获取1个的问题求助
问题描述
从服务器获取数据时使用Promise等待返回,当前遇到异常:从某页面返回至另一页面后,用于向其他组件传递客户任务的tasks数组,控制台打印显示包含3个SelectedCustomerTasks元素,但调用findTasksOfCustomer查找选中客户对应元素时,仅能得到一个元素。
控制台输出情况
在findTasksOfCustomer函数中打印this.customerTasks:
0: {customerId: '418', tasks: Array(1), openTasksAmount: 1} 1: {customerId: '503', tasks: Array(1), openTasksAmount: 1} 2: {customerId: '409', tasks: Array(4), openTasksAmount: 3}
但遍历该数组时,控制台仅输出:
{customerId: '418', tasks: Array(1), openTasksAmount: 1}
相关代码
loadTasks函数
private loadTasks() { return new Promise((resolve, reject) => { var tasks: tasks[] = []; this.customers.forEach(async (customer, index) => { var tasks = ( await this._taskClient.getCustomerTasks(customer.customerId).toPromise() ).map((x) => JSON.parse(x) as Task); var data: SelectedCustomerTasks = { customerId: customer.customerId, tasks: tasks, openTasksAmount: tasks.filter( (x) => x.output[0].valueBoolean !== true ).length, }; tasks.push(data); if (index == this.customers.length - 1) { resolve(tasks); } }); }); }
ngOnInit方法
public ngOnInit() { this.loadTasks().then((tasks: SelectedCustomerTasks[]) => { if (tasks.length > 0) { this.customerTasks = tasks; if (sessionStorage.getItem("customerId")) { this.selectedCustomer = this.customers.find( (x) => x.customerId == sessionStorage.getItem("customerId") ); if (this.selectedCustomer) { this.emitCustomerData(this.selectedCustomer, false); } } } }); }
emitCustomerData与findTasksOfCustomer函数
private async emitCustomerData(customer: Customer){ this.selectedCustomerEvent.emit(this.findTasksOfCustomer(customer)); } private findTasksOfCustomer(customer: Customer): SelectedCustomerTasks { return this.customerTasks.find((x) => x.customerId == customer.customerId ); }
问题原因与修复方案
核心问题:异步逻辑处理错误
forEach不支持异步等待:forEach会直接启动所有异步请求,不会等待前一个请求完成再执行下一个,导致你判断index == this.customers.length - 1时,前面的异步请求大概率还没完成,此时resolve出去的数组只有最后一个客户的数据。后续其他请求完成后再往数组里push数据,控制台打印的是补全后的数组,但你第一次查找时用的是不完整的数组。- 变量名冲突:循环内重新声明了
var tasks,直接覆盖了外层用来收集所有客户任务的数组,导致外层数组根本没被正确填充。
修复步骤
方案1:用for...of实现串行异步请求
替换forEach为支持异步等待的for...of,同时修正变量名冲突:
private async loadTasks() { const tasks: SelectedCustomerTasks[] = []; for (const customer of this.customers) { // 修改变量名,避免和外层数组冲突 const customerTasks = ( await this._taskClient.getCustomerTasks(customer.customerId).toPromise() ).map((x) => JSON.parse(x) as Task); const data: SelectedCustomerTasks = { customerId: customer.customerId, tasks: customerTasks, openTasksAmount: customerTasks.filter( (x) => x.output[0].valueBoolean !== true ).length, }; tasks.push(data); } return tasks; }
同步修改ngOnInit调用:
public async ngOnInit() { const tasks = await this.loadTasks(); if (tasks.length > 0) { this.customerTasks = tasks; const storedCustomerId = sessionStorage.getItem("customerId"); if (storedCustomerId) { this.selectedCustomer = this.customers.find( (x) => x.customerId === storedCustomerId ); if (this.selectedCustomer) { this.emitCustomerData(this.selectedCustomer); } } } }
方案2:用forkJoin实现并行异步请求(性能更优)
如果不需要串行请求,建议用forkJoin同时发起所有请求,等待全部完成后返回完整数组:
private loadTasks() { const taskObservables = this.customers.map(customer => this._taskClient.getCustomerTasks(customer.customerId).pipe( map(tasks => { const parsedTasks = tasks.map(x => JSON.parse(x) as Task); return { customerId: customer.customerId, tasks: parsedTasks, openTasksAmount: parsedTasks.filter(x => !x.output[0].valueBoolean).length } as SelectedCustomerTasks; }) ) ); return forkJoin(taskObservables).toPromise(); }
额外优化
- 用
===替代==进行全等判断,避免类型转换导致的潜在问题。 emitCustomerData内无异步操作,可去掉async关键字。
内容的提问来源于stack exchange,提问作者user22114465
相关产品推荐
相关产品推荐

