【问题标题】:Converting multiple nested promises and array of promises to Observables将多个嵌套的 Promise 和 Promise 数组转换为 Observables
【发布时间】:2019-05-19 23:38:33
【问题描述】:

我正在使用 TypeScript 将 AngularJS 应用程序转换为 Angular 7。

我在将一些复杂的嵌套 Promise 转换为 Observables 时遇到了一些问题。

这是我正在处理的代码示例:

signup.component.js

function SomethingSignupController(somethingApplication) {
    function activate() {
        getApplication();
    } 

    function getApplication() {
        vm.getFromServer = false;
        vm.promises = [];
        SomethingRepo.get().then(function(application) {
            vm.getFromServer = true;
            vm.application = application;
            vm.promises.push(Something.getCompany().then(function(company) {
                vm.company = company;
                if (vm.company.structure === ‘more_25’) {
                    return SomethingRepo.getAllOwners().then(function(owners) {
                        vm.owners = owners;
                        for(var i = 0; i < vm.owners.length; i++) {
                            vm.promises.push(getOwnerFiles(vm.owners[i]));
                        }
                    }
                }
            }
            vm.promises.push(SomethingRepo.getSomethingOne().then(function(somethingOne) {
                vm.somethingOne = somethingOne;
            }
            vm.promises.push(SomethingRepo.getSomethingTwo().then(function(somethingTwo) {
                vm.somethingTwo = somethingTwo;
            }
            vm.promises.push(SomethingRepo.getSomethingThree().then(function(somethingThree) {
                vm.somethingThree = somethingThree;
            }
            /* and a few more like the above */
            $q.all(vm.promises).then(function(){
                postGet();
            }).finally(function() {
                vm.promises = [];
            });
        }
    }

    function postGet() {
        /* does something with the data acquired from SomethingRepo */
    }

    /* when an application is send */
    function send() {
        somethingApplication.promises = [];
        somethingApplication.errors = [];
        if (vm.getFromServer) {
            update();
        } else { 
            create();
        }
    }

    function update() {
        somethingApplication.promises.push(SomethingRepo.update(vm.application).then(angular.noop, function(error) {
            somethingApplication.parseErrors(error, ‘Some error’);
        }));
        patchInfo();
    }

    function create() {

    }

    function patchInfo() {
        somethingApplication.promises.push(SomethingRepo.patchAccount(vm.account).then(angular.noop, function(error) {
            somethingApplication.parseErrors(error, ‘Account error: ‘);
        }
        /* a few more patches */
        $q.all(somethingApplication.promises).then(function() {
            /* display dialog */
        }, angular.noop).finally(function() {
            postGet();
            somethingApplication.promises = [];
            if (somethingApplication.errors.length >= 1) {
                vm.errors = somethingApplication.errors;
            }
        });
    }
}

somethingApplication.service.js

function somethingApplication(SomethingRepo) {
    var promises = [], errors = [];

    var service = {
        promises: promises;
        errors = errors;
        parseErrors: parseErrors;
    };

    return service; 


    function parseErrors(error, base_string) {
        angular.forEach(error.data.erros, function(value_params, key_params) {
            this.errors.push(base_string + ‘ ‘ + key_params.replace(/_/g, ‘ ‘) + ‘ ‘ + value_params);
        }, this);
    }
}

somethingRepo.js

function SomethingRepo(Server) {
    function get() {
        return Server.get(‘/something/application’, null, {noGlobal: true});
    }
}

我已经减少了文件,但它们包含更多这样的代码。 控制器的目的是为另一个网站创建或更新应用程序。在我的网站上,我有一个与另一个网站上的表单相对应的字段表单。如果您已经提交了申请,但想要更新它,您已经提交的信息将从其他网站加载。

问题是,为了创建或更新应用程序,许多不同的端点请求发布到。

在 AngularJS 中,我存储来自每个请求的 Promise,并在最后异步运行它们。在 TypeScript 和 Angular 中,我想使用 Observables 并订阅数据更改。

我该如何开始?如何从另一个 Observable 订阅 Observable 所需的参数?任何建议如何进行?

【问题讨论】:

  • Observable 支持 ToPromise 方法,将 Observable 转换为可调用的 Promise。如果您想保留Promise.all 方法,您可以。否则,您可以考虑使用 RxJs 建议的其他方法,例如 .concatMap、forkJoin 等。尽可能利用async await,这将帮助您跟踪它在迁移阶段所做的工作。
  • “我如何开始?如何订阅另一个 Observable 的所需参数?任何建议如何继续?”如果我理解正确,您正在寻找forkJoin。您可以将其与 from(promise) 结合使用以创建一个可观察的对象,该可观察对象等待一组承诺解决,然后发出已解决值的列表。
  • 我不想保留Promise 方法。你有一个具体的例子来说明我如何forkJoin 我的特定代码吗?不是我想让你做这项工作,但我很难将我读到的关于 forkJoin 的内容应用到我的代码中
  • 这可能会有所帮助 - stackoverflow.com/questions/39319279/…
  • @FrankfromDenmark forkJoin 与 Promise.all 完全一样:您提供 Observables 的数组(或列表)(angular 的 HttpClient.get 返回一个Observable 默认情况下),它的回调会触发所有解析的值。 FK82 提供了上面的官方文档。看看示例 5,它非常接近您的用例。

标签: javascript angular typescript promise


【解决方案1】:

这是一个示例,展示了如何在场景中轻松使用可观察对象 -

你的服务应该是这样的 -

import { Injectable } from '@angular/core';
import { AppConstants } from '../../app.constants';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class ExampleService {
    constructor(private appconstants: AppConstants, private http: HttpClient) { }

    get() {
        return this.http.get(this.appconstants.apiUrl);
    }

    getSomethingOne() {
        return this.http.get(this.appconstants.apiUrl1);
    }

    getSomethingTwo() {
        return this.http.get(this.appconstants.apiUrl2);
    }
}

然后只需在您的组件中使用它,如下所示 -

import { Component } from '@angular/core';
import { forkJoin } from 'rxjs';
import { ExampleService } from '../services/example.service';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.css']
})
export class ExampleComponent {

    data;
    dataOne;
    dataTwo;

    constructor(private exampleService: ExampleService) { }

    getApplication() {
        const combined = forkJoin([
            this.exampleService.get(),
            this.exampleService.getSomethingOne(),
            this.exampleService.getSomethingTwo()
        ]);
        combined.subscribe(res => {
            this.data = res[0];
            this.dataOne = res[1];
            this.dataTwo = res[2];
        });
    }
}

【讨论】:

  • 两个问题:1) 我不能让我的服务返回一个 Observable,例如:get(): Observable&lt;Application&gt; { return this.client.get&lt;Application&gt;(this.appconstants.apiUrl).pipe( map((item: any) =&gt; { return Object.assign(new Application(), item); }) ); } 2) 我将如何使用来自 forkJoin 的结果来创建另一个请求?我可以链接它,还是应该在之后提出单独的请求?
  • 1) 这种方法也很好,也是一种很好的做法。 2)您可以从您的函数中返回一个Observable - getApplication(),然后在其订阅中执行进一步的操作
  • 这是一个参考。用于创建 observable - medium.com/@luukgruijs/…
  • 非常感谢
猜你喜欢
  • 2019-09-26
  • 1970-01-01
  • 2017-03-22
  • 1970-01-01
  • 2015-06-06
  • 2018-09-19
  • 2017-08-08
  • 1970-01-01
  • 2022-06-21
相关资源
最近更新 更多