在 angular 代码中,foreach 循环在完成循环迭代之前跳到另一个函数
In angular code, foreach loop skips to the other function before finishing the loop iteration
private processArray(evts: Event[]): Promise<void> {
var auditsvc = this.auditSvc;
var t = this;
if(!evts || evts.length ==0 ) {
return;
}
let objArr: any[] = [];
evts.forEach( function (inpEvt) {
auditsvc.getAuditDetails(inpEvt.id).subscribe((data) => {
for(let i=0; i<data.length; i++){
let outObj = {};
outObj['Driver'] = inpEvt.driver.name;
outObj['Executive'] = inpEvt.executive.exec.name;
outObj['Point of Departure'] = inpEvt.pod;
outObj['Date of Departure'] = UtilService.dateToString(inpEvt.date);
outObj['Arrival Time'] = UtilService.timeToString(inpEvt.arrivalTime);
outObj['Departure Time'] = UtilService.timeToString(inpEvt.departureTime);
outObj['Action Timestamp'] = data[i].actionedOnTimestamp;
outObj['Modified By'] = data[i].modifiedBy;
outObj['Comment'] = data[i].comment;
objArr.push(outObj);
}
}, (err) => {
console.log(err);
}, () => {
});
});
if(objArr.length == 0) {
UtilService.openError(t.modalSvc,'No logs found.');
return;
}else{
t.exportAsXLSX(objArr);
}
}
没有执行for each循环,而是先执行下一个函数。我希望循环先迭代然后转到另一个函数作为循环 returns 其他函数所需的一些数据。
由于循环没有迭代,objArr长度为0,总是报'No logs found'错误
问题在于 auditsvc.getAuditDetails()
是一个异步操作,因此 evts.forEach
只是迭代 evts
,注册订阅——将它们放入异步队列——然后退出。 subscribe
回调函数直到稍后某个时间才会被调用,在异步操作完成之后,并且在您当前的代码已经检查了 objArr.length
.
之后
您需要做的是构建一个管道,其中检查 objArr.length
在 所有异步操作完成并填充后 objArr
.
一种方法是通过将 evts
中的每个 inpEvt
映射到获取其审计详细信息的相应 Observable 来创建一个 Observable 数组,如下所示:
const auditDetails$: Observable<any>[] = evts.map(inpEvt => {
return auditsvc.getAuditDetails(inpEvt.id).pipe(
map(data => ({ inpEvt, data })) // <-- need to pass inpEvt also because outObj will need it
);
});
然后您可以将该 Observable 数组传递给 RxJS forkJoin 以触发它们并将 return 它们的结果放在一个数组中:
forkJoin(auditDetails$).pipe( // <-- auditDetails$ is array of Observables
map((auditDetails: any[]) => { // <-- auditDetails is array of all Observable results, here passed to RxJS map operator
})
)
然后您可以使用 RxJS map 运算符将审计详细信息数据转换为您需要的 objArr
。
为此,在 RxJS map
投影函数中,您可以使用原生 JavaScript Array#map 将审计详细信息数组映射到 outObj
数组s,像这样:
forkJoin(auditDetails$).pipe(
map((auditDetails: any[]) => { // <-- RxJS map operator
return auditDetails.map(({ inpEvt, data }) => { // <-- native JS Array#map
const outObj = {};
for(let i=0; i<data.length; i++){
outObj['Driver'] = inpEvt.driver.name;
// ......
outObj['Comment'] = data[i].comment;
}
return outObj;
});
})
)
最后,订阅 Observable 管道,您将在 fully-populated 状态下获得 objArr
,您需要它:
forkJoin(auditDetails$).pipe(
map((auditDetails: any[]) => {
// ...
})
).subscribe(objArr => { // <-- final result is asynchronously-populated objArr
if (objArr.length == 0) {
UtilService.openError(t.modalSvc,'No logs found.');
return;
} else {
t.exportAsXLSX(objArr);
}
});
private processArray(evts: Event[]): Promise<void> {
var auditsvc = this.auditSvc;
var t = this;
if(!evts || evts.length ==0 ) {
return;
}
let objArr: any[] = [];
evts.forEach( function (inpEvt) {
auditsvc.getAuditDetails(inpEvt.id).subscribe((data) => {
for(let i=0; i<data.length; i++){
let outObj = {};
outObj['Driver'] = inpEvt.driver.name;
outObj['Executive'] = inpEvt.executive.exec.name;
outObj['Point of Departure'] = inpEvt.pod;
outObj['Date of Departure'] = UtilService.dateToString(inpEvt.date);
outObj['Arrival Time'] = UtilService.timeToString(inpEvt.arrivalTime);
outObj['Departure Time'] = UtilService.timeToString(inpEvt.departureTime);
outObj['Action Timestamp'] = data[i].actionedOnTimestamp;
outObj['Modified By'] = data[i].modifiedBy;
outObj['Comment'] = data[i].comment;
objArr.push(outObj);
}
}, (err) => {
console.log(err);
}, () => {
});
});
if(objArr.length == 0) {
UtilService.openError(t.modalSvc,'No logs found.');
return;
}else{
t.exportAsXLSX(objArr);
}
}
没有执行for each循环,而是先执行下一个函数。我希望循环先迭代然后转到另一个函数作为循环 returns 其他函数所需的一些数据。
由于循环没有迭代,objArr长度为0,总是报'No logs found'错误
问题在于 auditsvc.getAuditDetails()
是一个异步操作,因此 evts.forEach
只是迭代 evts
,注册订阅——将它们放入异步队列——然后退出。 subscribe
回调函数直到稍后某个时间才会被调用,在异步操作完成之后,并且在您当前的代码已经检查了 objArr.length
.
您需要做的是构建一个管道,其中检查 objArr.length
在 所有异步操作完成并填充后 objArr
.
一种方法是通过将 evts
中的每个 inpEvt
映射到获取其审计详细信息的相应 Observable 来创建一个 Observable 数组,如下所示:
const auditDetails$: Observable<any>[] = evts.map(inpEvt => {
return auditsvc.getAuditDetails(inpEvt.id).pipe(
map(data => ({ inpEvt, data })) // <-- need to pass inpEvt also because outObj will need it
);
});
然后您可以将该 Observable 数组传递给 RxJS forkJoin 以触发它们并将 return 它们的结果放在一个数组中:
forkJoin(auditDetails$).pipe( // <-- auditDetails$ is array of Observables
map((auditDetails: any[]) => { // <-- auditDetails is array of all Observable results, here passed to RxJS map operator
})
)
然后您可以使用 RxJS map 运算符将审计详细信息数据转换为您需要的 objArr
。
为此,在 RxJS map
投影函数中,您可以使用原生 JavaScript Array#map 将审计详细信息数组映射到 outObj
数组s,像这样:
forkJoin(auditDetails$).pipe(
map((auditDetails: any[]) => { // <-- RxJS map operator
return auditDetails.map(({ inpEvt, data }) => { // <-- native JS Array#map
const outObj = {};
for(let i=0; i<data.length; i++){
outObj['Driver'] = inpEvt.driver.name;
// ......
outObj['Comment'] = data[i].comment;
}
return outObj;
});
})
)
最后,订阅 Observable 管道,您将在 fully-populated 状态下获得 objArr
,您需要它:
forkJoin(auditDetails$).pipe(
map((auditDetails: any[]) => {
// ...
})
).subscribe(objArr => { // <-- final result is asynchronously-populated objArr
if (objArr.length == 0) {
UtilService.openError(t.modalSvc,'No logs found.');
return;
} else {
t.exportAsXLSX(objArr);
}
});