简体   繁体   English

Angular:这是重构“.subscribe()”中代码的最佳方式

[英]Angular: Which is the best way of refactoring the code inside ".subscribe()"

Let's say I have a component like this假设我有这样的组件

The Original Code:原始代码:

import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `<pre>{{ response | json }}</pre>`,
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  constructor(private _http: HttpClient) {
    this.fetchUsers();
  }

  response!: any;

  fetchUsers() {
    this._http.get(`https://jsonplaceholder.typicode.com/users`).subscribe(
      (resp) => {
        console.log(resp);
        this.response = resp;
      },
      (err) => {
        console.error(err);
        this.response = err;
      },
      () => {
        console.log('Subscription Complete');
      }
    );
  }
}

and I have following approaches to refactor the above code...我有以下方法来重构上面的代码......

Refactor approach 1:重构方法一:

import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `<pre>{{ response | json }}</pre>`,
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  constructor(private _http: HttpClient) {
    this.fetchUsers();
  }

  response!: any;

  onSubscribe = (resp: any) => {
    console.log(resp);
    this.response = resp;
  };

  onError = (err: any) => {
    console.error(err);
    this.response = err;
  };

  onCompletion = () => {
    console.log('Subscription Complete');
  };

  fetchUsers() {
    this._http
      .get(`https://jsonplaceholder.typicode.com/users`)
      .subscribe(this.onSubscribe, this.onError, this.onCompletion);
  }
}

Refactor approach 2:重构方法 2:

import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `<pre>{{ response | json }}</pre>`,
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  constructor(private _http: HttpClient) {
    this.fetchUsers();
  }

  response!: any;

  onSubscribe(resp: any) {
    console.log(resp);
    this.response = resp;
  }

  onError(err: any) {
    console.error(err);
    this.response = err;
  }

  onCompletion() {
    console.log('Subscription Complete');
  }

  fetchUsers() {
    this._http.get(`https://jsonplaceholder.typicode.com/users`).subscribe(
      (resp) => this.onSubscribe(resp),
      (err) => this.onError(err),
      () => this.onCompletion()
    );
  }
}

Refactor approach 3:重构方法 3:

import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `<pre>{{ response | json }}</pre>`,
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  constructor(private _http: HttpClient) {
    this.fetchUsers();
  }

  response!: any;

  fetchUsers() {
    this._http.get(`https://jsonplaceholder.typicode.com/users`).subscribe({
      next: (resp: any) => {
        console.log(resp);
        this.response = resp;
      },
      error: (err: any) => {
        console.error(err);
        this.response = err;
      },
      complete: () => {
        console.log('Subscription Complete');
      },
    });
  }
}

Refactor approach 4:重构方法 4:

import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `<pre>{{ response | json }}</pre>`,
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  constructor(private _http: HttpClient) {
    this.fetchUsers();
  }

  response!: any;

  onSubscribe = (resp: any) => {
    console.log(resp);
    this.response = resp;
  };

  onError = (err: any) => {
    console.error(err);
    this.response = err;
  };

  onCompletion = () => {
    console.log('Subscription Complete');
  };

  fetchUsers() {
    this._http.get(`https://jsonplaceholder.typicode.com/users`).subscribe({
      next: this.onSubscribe,
      error: this.onError,
      complete: this.onCompletion,
    });
  }
}

Refactor approach 5:重构方法 5:

import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `<pre>{{ response | json }}</pre>`,
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  constructor(private _http: HttpClient) {
    this.fetchUsers();
  }

  response!: any;

  onSubscribe(resp: any) {
    console.log(resp);
    this.response = resp;
  }

  onError(err: any) {
    console.error(err);
    this.response = err;
  }

  onCompletion() {
    console.log('Subscription Complete');
  }

  fetchUsers() {
    this._http.get(`https://jsonplaceholder.typicode.com/users`).subscribe({
      next: (resp: any) => this.onSubscribe(resp),
      error: (err: any) => this.onError(err),
      complete: () => this.onCompletion(),
    });
  }
}

Now the question is现在的问题是

Considering the performance (in the first place & readability the next) - which would be the best choice?考虑性能(首先是可读性)——哪个是最好的选择?

  1. Refactor approach 1?重构方法 1?
  2. Refactor approach 2?重构方法 2?
  3. Refactor approach 3?重构方法 3?
  4. Refactor approach 4?重构方法 4?
  5. Refactor approach 5?重构方法 5?
  6. The Original Code?原始代码?

I think that the best approach is the number 4 for the next reasons:我认为最好的方法是数字 4,原因如下:

Talking about readability, the way in that you pass three arguments on the subscription (next, error, complete) is actually deprecated for RxJS because function arguments can contribute to hard-to-read-code.谈到可读性,您在订阅中传递三个 arguments 的方式(下一个、错误、完成)实际上已被 RxJS 弃用,因为 function arguments 会导致代码难以阅读。 You can read more about it here你可以在这里读更多关于它的内容

instead, RxJS advises you to use a JS object like an argument where you define the code to the different callbacks相反,RxJS 建议您使用 JS 882829995402888 作为参数,您可以在其中定义不同回调的代码

({next: () =>{}, error: () =>{}, complete: () =>{})

And separating the code into functions can help you make it cleaner to read.将代码分成函数可以帮助您使其更清晰易读。

Talking about the performance if you pass an argument like a JS object to the subscription RxJS passes an empty function to one of the callbacks instead of you doing it on your own.谈论性能,如果您将 JS object 之类的参数传递给订阅 RxJS,则将空的 function 传递给其中一个回调,而不是您自己执行。

Personally, I'd refactor to a declarative approach就个人而言,我会重构为声明式方法

  1. Create a service to encapsulate all of the data access.创建一个服务来封装所有的数据访问。
  2. In the service, define a variable (not a method) to manage the Observable returned from the http get.在服务中,定义一个变量(不是方法)来管理从 http get 返回的 Observable。
  3. In the component, define a variable (not the constructor or life cycle hook) to manage the Observable returned from the service在组件中,定义一个变量(不是构造函数或生命周期钩子)来管理从服务返回的 Observable
  4. Use the async pipe in the template.在模板中使用async pipe。

Example Service:示例服务:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { tap } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class UserService {
  users$ = this.http
    .get(`https://jsonplaceholder.typicode.com/users`)
    .pipe(tap((response) => console.log(response)));

  constructor(private http: HttpClient) {}

  fetchUsers() {}
}

Example Component/template示例组件/模板

import { Component } from '@angular/core';
import { catchError } from 'rxjs';
import { UserService } from './user.service';

@Component({
  selector: 'my-app',
  template: `<pre>{{ users$ | async | json }}</pre>`,
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  errorMessage = '';

  users$ = this.userService.users$.pipe(
    catchError(err => this.errorMessage = err)
  )

  constructor(private userService: UserService) { }

}

See this for more information on this declarative pattern: https://youtu.be/0XPxUa8u-LY有关此声明模式的更多信息,请参阅: https://youtu.be/0XPxUa8u-LY

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

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