简体   繁体   English

Rxjs结合动态的可观察量

[英]Rxjs Combine dynamic amount of observables

I am creating a loader for @ngx-translate , that loads multiple JSON translation files from a directory based on the selected language. 我正在为@ ngx-translate创建一个加载器,该加载器根据所选语言从目录加载多个JSON翻译文件。

The way I am currently loading the files is via an index.json file that contains an array with names and extensions for the translation files for that language. 我当前加载文件的方式是通过index.json文件,该文件包含一个数组,该数组包含该语言的翻译文件的名称和扩展名。

The structure of the translation files is as follows: 翻译文件的结构如下:

- assets
  - i18n
    - index.json <-- Contains an array of translation file names
    - en_US
      - home.json
      - header.json
    - de_DE
      - home.json
      - header.json

An example of the index.json is as follows: index.json的示例如下:

[
  "home.json",
  "header.json"
]

Since the Angular HttpClientModule cannot load the contents of a directory or the names of files in a directory (it can only load single json files) I need to define the names in the index.json . 由于Angular HttpClientModule无法加载目录的内容或目录中文件的名称(它只能加载单个json文件),因此我需要在index.json定义名称。

This also means I have to first load the index.json and then load all the other files in the directory. 这也意味着我必须先加载index.json,然后再加载目录中的所有其他文件。

In code this means the following: 在代码中,这意味着:

  1. Load the index.json 加载index.json
  2. Loop over the array of file names 循环遍历文件名数组
  3. Load every file in a separate request 在单独的请求中加载每个文件
  4. When all finished combine all the file contents into one object 全部完成后,将所有文件内容合并为一个对象

What I've tried 我尝试过的

 public getTranslation(language: string): Observable<any> {
    return this.getIndexFile(language)
      .pipe(
        map((fileNames: string[]) => {
          const promises = [];

          for (const name of fileNames) {
            const path = Translation.replaceUrlPlaceholder(this.path, language);
            promises.push(this.http.get(path + '/' + name + '.json').toPromise());
          }

          return Promise.all(promises);
        }),
      );
  }

So I've tried this with promises, but this obviously doesn't work (since an observable must be returned). 所以我已经尝试过用Promise进行尝试,但这显然行不通(因为必须返回一个Observable)。 Also the solution described here doesn't work for me, since I need to dynamicatlly create an unlimited amount of observables and wait for them to finish before I can start on step 4. (combine all files). 同样, 这里描述的解决方案对我不起作用,因为我需要动态地创建无限数量的可观察对象,并等待它们完成之后才能开始第4步。(合并所有文件)。

What should be the correct way to do this? 正确的方法应该是什么?


  • Angular 7.1.0 7.1.0
  • RxJS 6.3.3 RxJS 6.3.3
  • @ngx-translate/core 11.0.1 @ ngx-translate / core 11.0.1

Update 更新

Stackblitz here: Combining observables Stackblitz在这里: 结合可观察物

So after searching and trying some more I found the solution to my answer. 因此,在搜索并尝试了更多方法之后,我找到了答案的解决方案。 There where 2 problems: 那里有两个问题:

1. Flatmap vs Map 1.平面图与地图

I was using a map() instead of a flatMap . 我使用的是map()而不是flatMap The difference is that the flatMap will execute when the first observable has finished. 区别在于,当第一个可观察对象完成时,flatMap将执行。 This way the subscribe won't get the result until the flatMap observable has finished. 这样,直到flatMap observable完成,订阅才能获得结果。

2. Promise.all vs forkJoin 2. Promise.all与fork

The observable equivalent of Promise.all() is forkJoin() . Promise.all()的可观察等效项是forkJoin() ForkJoin wil execute all observables in parallel and returns the result of all observables in one array. ForkJoin将并行执行所有可观察变量,并在一个数组中返回所有可观察变量的结果。


The result 结果

So updating the code above will result in the following stackblitz: solution 因此,更新上面的代码将导致以下堆栈闪电: 解决方案

Or in code: 或在代码中:

  public getTranslation(language: string): Observable<any> {
    return this.getIndexFile(language)
      .pipe(
        flatMap((fileNames: string[]) => {
          const observables: Observable<any>[] = [];

          for (const name of fileNames) {
            const path = 'assets/i18n/' + language + '/' + name + '.json';
            observables.push(this.http.get(path));
          }

          // Run all the observables in parallel
          return forkJoin(observables);
        }),
      );

Separation of Concern 关注点分离

My code contains multiple actions in one function which make it hard to test. 我的代码在一个函数中包含多个动作,这使其很难测试。 So that should be separated. 所以应该分开。 @trichetriche made a version which includes separation of concern. @trichetriche制作了一个包含关注点分离的版本。

See his Stackblitz for the code: Stackblitz 请参阅他的Stackblitz以获取代码: Stackblitz

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

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