简体   繁体   English

Rxjs 没有执行ConcatMap

[英]ConcatMap is not executed in Rxjs

I am writing a file upload component.我正在写一个文件上传组件。 At first I check if a file exists and if so I prompt a user to either choose to save a copy or overwrite the existing file.首先,我检查文件是否存在,如果存在,我会提示用户选择保存副本或覆盖现有文件。 After the existence check I want to upload the file, but if the user chooses to save as a copy the existence check has to be done again in a recursive manner.存在性检查后我想上传文件,但如果用户选择另存为副本,则必须以递归方式再次进行存在性检查。 This means that it could and should happen that multiple observables are chained and executed one after another.这意味着它可能而且应该发生多个可观察对象被链接起来并一个接一个地执行。

But here is the bug: The observable I return in the expression-function is not executed, although it is chained by the use of the concatMap pipe.但这是一个错误:我在表达式函数中返回的可观察对象没有被执行,尽管它是通过使用concatMap pipe 链接起来的。

Why is this not behaving the way I intended it to behave?为什么这不符合我的预期?

The code looks like this:代码如下所示:

  onDocumentsUploaded(documents: CustomDocument[]) {
    console.log(documents)
    documents = documents.map(document => {
      return {
        ...document,
        fullName: document.name + "." + document.extension
      }
    });

    for (let document of documents) {
      this.sub.add(
        this.handleUpload(document).subscribe()
      );
    }
  }

  private handleUpload(document: CustomDocument): Observable<CustomDocument[]> {
    return this.documentService.checkIfExists(document).pipe(
      concatMap(exists => this.expression(document, exists))
    );
  }

  private expression(document: CustomDocument, exists: boolean): Observable<CustomDocument[]> {
    let subject$ = new Subject<CustomDocument[]>();
    if (exists) {
      this.confirmationService.confirm({
        header: this.translate.instant("documentUpload.confirmation.header"),
        message: this.translate.instant("documentUpload.confirmation.message", { fileName: "'" + document.fullName + "'" }),
        icon: 'pi pi-info-circle',
        accept: () => {
          subject$.pipe(
            concatMap(_ => this.handleUpload({
              ...document,
              name: document.name + " (Copy)",
              fullName: document.name + "(Copy)" + "." + document.extension
            }).pipe(
              tap(x => console.log("handleUpload"))
            ))
          );
        },
        reject: () => {
          subject$.pipe(
            concatMap(_ => this.documentService.upload(document))
          );
        }
      });
      return subject$.asObservable();
    }
    else {
      return this.documentService.upload(document);
    }
  }

In the function passed to accept , you are pipeing the subject$ though the concatMap , but you are ignoring the result observable.在传递给accept的 function 中,您将subject$通过concatMap进行管道传输,但您忽略了可观察到的结果。

Note that calling the .pipe() does not modify the original observable (or subject) in any way, but rather creates a new observable with the operators applied.请注意,调用.pipe()不会以任何方式修改原始可观察对象(或主题),而是创建一个应用了运算符的新可观察对象。

I think that what you'd like to do here is to return the result of the subject$.pipe(...) instead of the subject$.asObservable() .我认为您想在这里做的是返回subject$.pipe(...)而不是subject$.asObservable()的结果。

Based on your comment that the confirmationService.confirm is thread blocking, the use of the Subject in this case in unnecessary.根据您关于confirmationService.confirm是线程阻塞的评论,在这种情况下使用Subject是不必要的。

You can do something like this instead.你可以做这样的事情。

private handleUpload(document: CustomDocument): Observable<CustomDocument> {
  return this.documentService.checkIfExists(document).pipe(
    concatMap((exists) => 
      exists
      ? this.confirmAction(document) 
      : this.documentService.upload(document)
    )
  );
}

private confirmAction(document: CustomDocument): Observable<CustomDocument> {
  //variable to save the 'result' of the confirm method      
  let action$: Observable<CustomDocument>; 

  this.confirmationService.confirm({
    header: this.translate.instant("documentUpload.confirmation.header"),
    message: this.translate.instant("documentUpload.confirmation.message", { fileName: "'" + document.fullName + "'" }),
    icon: 'pi pi-info-circle',
    accept: () => {
      action$ = this.handleUpload({
        ...document,
        name: document.name + " (Copy)",
        fullName: document.name + "(Copy)" + "." + document.extension
      })
    },
    reject: () => {
      action$ = this.documentService.upload(document))
    }
  }  
    
  // since the confirm() is thread-blocking, the following return statement
  // won't be executed until the confirm method completes.  
  return action$; 
}

Btw the Subject example wasn`t working for two main reasons.顺便说一句, Subject的例子没有工作主要有两个原因。

  1. As @kszksz pointed out in his comment, subject$.pipe() does not modify the original subject$ , it creates a new observable.正如@kszksz 在他的评论中指出的那样, subject$.pipe()不会修改原始subject$ ,它会创建一个新的可观察对象。 So you were returning an incorrect source.所以你返回的来源不正确。
  2. In order to emit a notification in a Subject you need to call to its method next with the value.为了next Subject中发出通知,您需要使用该值调用它的方法。 (ie. subject$.next(value) ) (即subject$.next(value)

But as I pointed out at the beginning in this case its use is not required and just overcomplicate the code.但正如我在开始时指出的那样,在这种情况下,它的使用不是必需的,只会使代码过于复杂。

Cheers干杯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM