如何延迟可观察的订阅以从第一个可观察的

时间:2016-12-08 16:44:18

标签: angular typescript rxjs observable

在我的angular2应用程序中,我想按顺序执行可观察的订阅但我得到错误,因为第一个订阅有一个方法,我认为需要花费很多时间。我为不同的组件提供服务,以便它们可以缓存我的数据并可供所有组件使用。我是Http Observables的新手,不知道他们执行的顺序。

PriceList.service.ts

export class PriceListService
{
    private priceLists : PriceList[];
    private observable : Observable<any>;
    public getAll()
    {
        if(this.priceLists)
        {
            return Observable.of(this.priceLists);
        }
        else if (this.observable)
        {
            return this.observable;
        }
        else
        {
            this.observable = this.authHttp.get(this.appService.getApiUrl() + "api/price-list/list")
                .map(response => {
                    this.observable = null;
                    if(response.status == 400)
                    {
                        return "Failure";
                    }
                    else if(response.status == 200)
                    {
                        let myJson = response.json();
                        this.priceLists = myJson.data.priceList;
                        return this.priceLists;
                    }
                })
                .share();
            return this.observable;
        }
    }
}

Product.service.ts

export class ProductService
{
    products : Product[];
    observable : Observable<any>;
    priceLists : any;
    priceListMap : Map<number, any> = new Map<number, any>();
    defaultPriceList : Map<number, any> = new Map<number, any>();
    productMap : Map<number , any> = new Map<number , any>();
    defaultPriceListId : number;
    public getActiveProducts()
    {
        if(this.products)
        {
            return Observable.of(this.products);
        }
        else if (this.observable)
        {
            return this.observable;
        }
        else
        {
            this.observable = this.authHttp.get(this.appService.getApiUrl() + "api/product/list/active")
                .map(response => {
                    this.observable = null;
                    if(response.status == 400)
                    {
                        return "Failure";
                    }
                    else if(response.status == 200)
                    {
                        let myJson = response.json();
                        this.products = myJson.data.products;
                        this.getPriceLists();
                        return this.products;
                    }
                })
                .share();
            return this.observable;
        }
    }
    getPriceLists()
    {
        this.priceListService.getAll().subscribe(
            success => { this.priceLists = success; },
            error => {},
            ()=> { this.populatePriceListMap(); }
        );
    }
    populatePriceListMap()
    {
        for(let priceList of this.priceLists)
        {
            for(let product of this.products)
            {
                for(let prices of product.prices)
                {
                    if(priceList.id == prices.priceList.id)
                    {
                        this.productMap.set(product.id , {price : prices.price , discount : prices.discount});
                    }
                }
            }
            if(priceList.isDefault == 1)
            {
                this.defaultPriceList.set(priceList.id , this.productMap);
                this.defaultPriceListId = priceList.id;
            }
            this.priceListMap.set(priceList.id , this.productMap);
            this.productMap = new Map<number , any>();
        }
    }
    getDefaultList()
    {
        if(this.defaultPriceList){
            return Observable.of(this.defaultPriceList.get(this.defaultPriceListId));
        }
    }
}

ListProduct.component.ts

export class ListProductsComponent implements OnInit
{
    products:any = null;
    pricesMap : Map<number, any> = new Map<number, any>();
    prices:any = [];
    discounts:any = [];
    ngOnInit()
    { 
        this.productService.getActiveProducts().subscribe(
            success =>{
                this.products = success;
            },
            error =>{},
            () =>{
                this.populatePrices();
            }
        );
    }
    populatePrices()
    {
        this.productService.getDefaultList().subscribe(
            success =>
            {
                this.pricesMap = success;
            },
            error =>{},
            ()=>{
                for (let product of this.products)
                {
                    let myObject = this.pricesMap.get(product.id);
                    this.prices[product.id] = myObject.price;
                    this.discounts[product.id] = myObject.discount;
                }
            }
        );
    }
}

错误

error

它应该做什么

我希望我的组件按此顺序执行功能。

  1. 我想执行getActiveProducts(),以便我的productService从api获取产品并存储它们。

  2. 我想执行getPriceLists() productService来从其他服务获取数据并将其存储在productService中。

  3. 我想执行populatePriceListMap(),以便填充不同的服务属性。

  4. 我想在我的组件中执行populatePrices()并将值分配给不同的属性。

  5. 我正面临的问题

    我认为它执行第1步和第4步,而第1步正在执行其工作。我想显示在步骤4中设置的属性,但它不会分配它们并给出错误。

2 个答案:

答案 0 :(得分:0)

您已在订阅中的pricesMap回调中设置此onNext变量,然后在onCompleted回调中访问该变量。 您显然将其设置为未定义的值,该值作为值传入。那是错误。

至于最佳做法,您可能希望了解如何执行Rx in an Rx-like way

答案 1 :(得分:0)

如果你可以同时接听并行(一个呼叫不依赖于另一个,只需要同步结果),那么我建议使用forkJoin运算符。它是处理并行调用的地方,它等待它们全部完成之后再为每个调用抽取结果。

例如: 编辑:之前有一个错误:我把第二个observable的take(2)放到了它应该采取的(1)

var obs1 = this.authHttp.get(firstUrl).take(1);
var obs2 = this.authHttp.get(secondUrl).take(1);
Observable.forkJoin(obs1, obs2)
          .subscribe(responseArray => {
               // Do something 
               // where responseArray[0] is the response you receive from the first get call, obs1
               // responseArray[1] is the response you receive from the second get call, obs2
          });

您可以在此处详细了解:https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/forkjoin.md

但是,如果你想运行它们顺序(第二次get调用需要来自第一个get的响应的参数),那么你正在寻找switchMap运算符。因此,使用上面的相同obs1和obs2,你想做:

obs1.do(resp1 => {
       // Anything you want to do with the first response before you fire off the second one
  }).switchMap(obs2)
    .subscribe(resp2 => {
               // Do something 
    });