【发布时间】:2021-02-11 13:29:05
【问题描述】:
我正在尝试自动化更新程序后端中某些数据的过程。 我正在使用我的 Angular 前端,在那里我创建了一个只有主用户才能访问的功能,这应该让他登录每个管理(租户),在那里它将下载一些内部包含错误数据的对象,从谷歌服务询问正确的数据并在后端更新数据,并为每个租户执行所有这些操作。
我想把每一个操作写成一个 observable 并使用 concat 来按顺序做所有事情,但是在我完成获取正确数据之前,我在一个水龙头里做的,它已经尝试登录下一个租户,所以当它实际上有正确的数据时,他将无法将它们上传到后端,因为它会拒绝它们来自错误的租户。
我认为这个问题是由水龙头中需要的长时间操作引起的(我需要做一些事情需要更多时间),。
这是我的代码 sn-p(没有无关的东西):
const obsList = [] as Observable<any>[];
this.assignedTenants.forEach(tenant => {
const obsList2 = [] as Observable<any>[];
obsList.push(this.authenticationService.login(new Credentials(usr, psw), tenant.id));
obsList.push(this.structureService.getStructuresWithWrongAltitude()
.pipe(tap(structuresReceived => {
obsList2 = [] as Observable<any>[];
if (structuresReceived != null && structuresReceived.length > 0) {
structuresReceived.forEach(s => {
this.getElevation(new google.maps.LatLng(s.centro.coordinates[0], s.centro.coordinates[1]))
.then(a => {
s.centroAltitudine = a;
this.obsList2.push(this.structureService.putStructure(s));
})
.catch();
});
}
})));
obsList.push(forkJoin(obsList2)
.pipe(tap(() => this.storageService.logout())));
});
concat(...obsList).subscribe();
如你所见,这段代码应该为每个租户创建并执行 3 个 observable,第一个用于登录,第二个用于获取错误数据,获取正确数据并为第三个做准备,这将更新数据。 正如我所说,通常当从第二个可观察对象 getStructuresWithWrongAltitude 进入水龙头时,我已经可以通过使用日志看到它尝试登录到其他租户。
我的理论是,一旦它得到错误的数据,它就会尝试执行仍然无效的第三个 observable,然后转到下一个租户,但我不知道如何解决这个问题。
我需要一种方法让第二个 observable 在点击完成之前不发射,或者另一种方法来防止 concat 在其他操作完成之前继续
感谢您的帮助
编辑:
我能够通过将 getElevation(它返回一个承诺)设置为一个可观察列表来解决这个问题,该列表又会创建一个新的可观察列表来保存数据。
正如我之前所说,我需要做一些非常相似的事情,不同的是这次水龙头实际上需要做很多需要很长时间的计算,所以我不能使用相同的修复,因此我的问题仍然存在:我可以让 concat 等到点击完成吗?
为澄清而编辑 2
正如我在上次编辑中所说,通过将 tap 中的内容转换为其他 observables 解决了该特定示例,但我在另一个函数中遇到了几乎相同的问题
此功能需要在文件夹中查找文件,然后才能上传文件
const folderInput = this.folderInput.nativeElement;
folderInput.onchange = () => {
this.filesUploaded = folderInput.files;
const obsList = [] as any[];
this.assignedTenants.forEach(tenant => {
const obsList2 = [] as Observable<any>[];
obsList.push(this.authenticationService.login(new Credentials(usr, psw), tenant.id));
obsList.push(this.fileService.getAll()
.pipe(
tap(filesReceived => {
if (filesReceived != null && filesReceived.length > 0) {
console.log('upload picture: received list of files to update');
let i = filesReceived?.length;
filesReceived?.forEach(f => {
const pathReceived = (f.originalFilename as string).substr(1).split('\\');
let found = false;
let index = -1;
// searching the file in the folder
//...
if (found) {
console.log('found a file');
const selectedFile = this.filesUploaded[index];
const formData = new FormData();
formData.append('file', selectedFile, selectedFile.name);
obsList2.push(this.fileService.updateFile(formData, f.id));
}
i--;
});
console.log('upload picture: updated obsList2');
obsList.push(forkJoin(obsList2).subscribe(() => {
console.log('upload picture: uploaded pictures');
this.storageService.logout();
}));
}
}))
);
});
this.loadingIndicatorService.loading$.next(true);
let counter = obsList.length;
concat(...obsList).subscribe(() => {
counter--;
console.log('upload pictures: remaining phases: ' + counter);
if (counter <= 0) {
this.loadingIndicatorService.loading$.next(false);
}
});
};
folderInput.click();
【问题讨论】:
-
这里有几处不明白的地方,但第一个与常量
obsList2有关。您在第三行声明它,然后在第七行使用代码obsList2 = [] as Observable<any>[];重置它。你确定这在 Typescript 中真的有效吗?一旦我们澄清了这一点,我们就可以继续进行其余的工作。 -
你试过这个 SO 帖子吗? stackoverflow.com/questions/43336549/…。本文还讨论了事件排序 - juristr.com/blog/2019/01/Guarantee-Event-Order-with-RxJS
-
@Picci 是的,它有效,我只是再次将其设为空以确保,但它不会产生任何错误或警告
-
@AndyDangerGagne 问题不是按顺序执行它们,而是让它们等待第二个管道的水龙头,这需要一些时间。正如我所说,示例中的问题已解决,但它不适用于更复杂的水龙头。
标签: rxjs concatenation rxjs-observables rxjs-pipeable-operators rxjs-pipe