【问题标题】:Observable in for loop?在 for 循环中可观察到?
【发布时间】:2022-01-26 17:38:17
【问题描述】:

我想在 for 循环中调用一个可观察的 REST 服务。它返回 base64 编码的 csv 文件。我想对其进行解码并将其连接成一个字符串并返回它。之后,我尝试订阅该方法并单击 DOM 进行下载。我得到只有"\r\n" 的空字符串。为什么不等 REST 返回文件才返回?

downloadFilesAndConcatenate(): Observable<any> {
    let concatenatedFileDecoded: string = '\r\n';
    for (let i = 0; i < this.fileIDs.length; i++) {
      this.restService.getFile(this.fileIDs[i]).subscribe(response => {
        this.fileResultSet = response;
        this.message = response.message;
        this.file = this.fileResultSet.result;
        let fileCSVbase64 = this.file.fileBytes
        let fileCSVDecoded = atob(fileCSVbase64);
        concatenatedFileDecoded += fileCSVDecoded;
      },
      error => {
        this.message = error.error.message;
      });

      return new Observable( observer => {
        observer.next(concatenatedFileDecoded)
        observer.complete();
      });
    }
  }

然后我订阅它:

download() {
    if (this.dateEnd !== null && typeof this.dateEnd !== "undefined") {
      debugger;
      this.downloadFilesAndConcatenate()  // Multiple files
        .subscribe( 
          (result) => {
            debugger;
            const link = document.createElement( 'a' );
            link.style.display = 'none';
            document.body.appendChild( link );

            const blob = new Blob([result], {type: 'text/csv'});
            const objectURL = URL.createObjectURL(blob); 

            link.href = objectURL;
            link.href = URL.createObjectURL(blob);
            link.download =  this.file.name;
            link.click();
          },
          (err) => {
            console.error(err);
          },
          () => console.log("download observable complete")
        );
    } else {
      this.downloadFile();  // Only one file
    }
  }

【问题讨论】:

    标签: angular typescript rxjs observable subscribe


    【解决方案1】:

    因为它是异步代码。预计同步代码将比异步更早执行。 正确的代码是这样的

    downloadFilesAndConcatenate(): Observable<string> {
        return forkJoin(this.fileIDs.map(id => this.restService.getFile(id))).pipe(
          map(responses => '\r\n'+responses.map(r => atob(r.result.fileBytes)).join(''))
          catchError(e => this.message = e.error.message)
        );
      }
    

    【讨论】:

    • 实现 catchError 并从 RxJS 导入 forkJoin。但是,对于第二个map(在管道中)我得到Cannot find name 'map'. Did you mean 'Map'?ts(2552) lib.es2015.collection.d.ts(36, 13): 'Map' is declared here. 如果我这样做,那么我得到:Value of type 'MapConstructor' is not callable. Did you mean to include 'new'?
    • 它也应该从rxjs以及catchError导入
    • Tnx,从这里导入import { map, catchError } from 'rxjs/operators';
    • 所有文件都下载并加入到一个 csv 中。可以了,谢谢!
    猜你喜欢
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    相关资源
    最近更新 更多