尝试在我当前的Angular应用程序中使用异步管道而不是订阅

时间:2017-09-23 00:39:04

标签: angular typescript rxjs observable

我正在开发一个Angular(v4)应用程序。与任何其他Web应用程序一样,此应用程序也有HTTP个请求,对于每个请求,我都订阅了获取数据并在UI上显示它们。我一直在阅读async管道的使用情况以及为什么它比subscribe更好。根据我的阅读,它肯定比普通的subscribe方法有好处,我确信我应该在我的应用程序中使用它,但我不知道如何用这个aync管道构建我的应用程序而不是subscribe。让我发布我的应用程序的结构:

我有一个服务层,可以向后端发出Http请求,例如:

  

一些-service.component.ts

@Injectable()
export class SomeService {
 constructor(private http: HttpClient) {
}
 getSomething() {
    return this.http.get(`${this.baseUrl}/${'test'}`);
}
}

上面的服务为我的组件提供了一个Observable,我通常订阅它,如下所示:

  

一些-component.ts

    @Component({
    selector: 'some-app',
    templateUrl: './some.component.html',
    styleUrls: []
})
export class SomeComponent {
 constructor(private someService: SomeService) {
    }
  getSomething() {
        this.someService
            .getSomething()
            .subscribe(
                // the first argument is a function which runs on success
                (data) => {
                  // DO SOME DATA TRANSFORMATION HERE
                                    },
                // the second argument is a function which runs on error
                (err: HttpErrorResponse) => {
                    this.exceptionService.errorResponse(err);
                },
                // the third argument is a function which runs on completion
                () => {
                      // MAKE SOME FUNCTION CALL
                                }
            );
    }
}

以上是我如何订阅一般HTTP响应的一般结构。我想摆脱这个subscribe并使用async代替。但是,我的问题是,我在收到数据(如上所示)或某个时间data transformation完成I make some function call from the(如上所示)时做了一些observer并且通过此类操作,我不确定一旦切换到async,我将如何进行这些操作。

对于数据转换,我想,我可以在我的服务中做到这一点(虽然不确定)但是我现在如何进行函数调用。

任何输入都将受到高度赞赏。如果我的问题需要更多澄清,也请告诉我。谢谢!

5 个答案:

答案 0 :(得分:2)

我将以更通用的方式根据您的代码回答

<强> foo.service.ts

awk '
FNR==1 {                   # get the column number of PREDICT column for each file
    for(i=1;i<=NF;i++)
        if($i=="PREDICT")
            p=i            # set it to p
}
$p==646 {                  # if p==646, we have a match
    print FILENAME         # print the filename
    nextfile               # and move on to the next file
}' file1 file2             # all the candicate files

在地图操作员中,您可以进行操作并返回新状态

<强> foo.component.ts

导入rxjs @Injectable() export class FooService { constructor(private _http:HttpClient){ } public getFoo():Observable<any> { return this._http.get(`${API_URL}`).map(r => r.json()); } } 运算符以调用最后的方法

finally

<强> foo.html

import 'rxjs/add/operators/finally'; export class FooComponent { public bar$:Obervable<any>; constructor(private _foo:FooService){} getBar(): void { this.bar$ = this._foo.getFoo() .finally(() => { // INVOKE DESIRED METHOD }); } }

这将创建div包装元素并为其提供visiblity隐藏选项,因此不需要? '猫王'运营商

您还可以根据您的要求修改ngIf表达式

答案 1 :(得分:1)

1。接收数据后的数据转换

当您使用observable时,您可以使用一个非常常见的运算符将传入的数据转换为其他内容:地图运算符documentation here)。 “ Map运算符将您选择的函数应用于源Observable发出的每个项目,并返回一个Observable,它发出这些函数应用程序的结果。

  

some-service.component.ts(已修改)

// Don't forget this, or it will cause errors
import 'rxjs/add/operator/map';

@Injectable()
export class SomeService {
  constructor(private http: HttpClient) {
}
getSomething() {
  return this.http.get(`${this.baseUrl}/${'test'}`)
    .map(data => transformData(data));
}
  

一些-component.ts

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

  constructor(private someService: SomeService) { }

  getSomething() {
    this.someService
      .getSomething()
        .subscribe(
          // the first argument is a function which runs on success
          (data) => {

            // DO SOMETHING WITH DATA TRANSFORMED HERE
                                },
          // the second argument is a function which runs on error
          (err: HttpErrorResponse) => {

            this.exceptionService.errorResponse(err);

          },
          // the third argument is a function which runs on completion
          () => {

            // MAKE SOME FUNCTION CALL

          }
        );
  }
}

请注意,您还可以在some-component.ts中再次使用map运算符(在导入之后)。你也可以决定一次使用它,只在some-component.ts中使用它。或者您可以将函数传递给this.someService.getSomething(myFunction)来转换数据。请参阅下面的服务实现。

// Don't forget this, or it will cause errors
import 'rxjs/add/operator/map';

@Injectable()
export class SomeService {
  constructor(private http: HttpClient) {
}
getSomething(myFunction) {
  return this.http.get(`${this.baseUrl}/${'test'}`)
    .map(data => myFunction(data));
}

2。使用异步管道而不是订阅

要使用异步管道,请将Observable存储在属性中。

import { Component, OnInit } from '@angular/core'

@Component({
  selector: 'some-app',
  templateUrl: './some.component.html',
  styleUrls: []
})
export class SomeComponent implements OnInit {

  myObservable;

  constructor(private someService: SomeService) { }

  ngOnInit() {
    this.myObservable = this.getSomething();
  }

  getSomething() {
    return this.someService.getSomething();
  }
}

然后,将异步管道应用于您的模板(documentation here):

<p>{{ myObservable | async }}</p>

或者,正如所说的Optiq(当你处理对象的例子时):

<div *ngFor="let a of myObservable | async">
  <p>{{ a.whatever }}</p>
</div>

请注意,您不能将异步管道应用于函数。

3。收到数据后执行某些操作

最后,您可以处理收到数据的情况。见下文:

import { Component, OnInit } from '@angular/core'

@Component({
  selector: 'some-app',
  templateUrl: './some.component.html',
  styleUrls: []
})
export class SomeComponent implements OnInit {

  myObservable;

  constructor(private someService: SomeService) { }

  ngOnInit() {
    this.myObservable = this.getSomething();
  }

  getSomething() {
    const obs = this.someService.getSomething();
    obs.subscribe((data) => {
      // Handle success
    }, (err) => {
      // Handle error
    }, () => {
      // Make some function call
    })
    return obs;
  }
}

答案 2 :(得分:0)

async pipe在您的模板绑定中应用,如此

<div *ngFor="let a of yourData | async">
    <p>{{a.whatever}}</p>
</div>

如果您不知道a是您想要调用每个数组的名称,yourData是您班级中您正在迭代的变量的名称从

我不会说这是&#34;更好&#34;而不是使用subscribe(),因为它不是做同样事情的另一种方式。事实上,async管道可以帮助你的绑定处理订阅,因为当一个组件加载它时,它可能会在数据到达之前调用变量的值,这会给你一堆undefined错误或者看不到console.log()中的任何内容,即使您在模板中看到它具有约束力。

你试图通过嗅探async管道来消除什么头痛?这听起来像你需要了解的其他东西,你还不知道如何要求它,这是尝试发现它。

答案 3 :(得分:0)

1)您可以创建linked answer来进行数据转换(custom pipe

2)您可以使用docs方法来处理错误处理(catch()

答案 4 :(得分:0)

优势:

  1. 它将自动订阅&&取消订阅组件Init && 破坏。不再使用subscribe()和unsubscribe():)
  2. 您不必使用?(elvis运算符)
  3. 更少的代码行。

注意::您一定会喜欢这样,代码仅供参考。请逐步实施以下代码,以测试您的API数据。

// call your imports
@Component({
   selector: 'some-app',
   template: '
     <ng-container *ngIf="data$ | async as data">
         <input [value]="data.new" />
         <div *ngFor="let val of data">
            // some more todo things
         </div>
     </ng-container>
   '
})
export class SomeComponent {
     data$: Observable<data>;
}