Angular:这是重构".subscribe()"内部代码的最佳方式



假设我有一个这样的组件

原始代码:

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');
}
);
}
}

和我有以下方法来重构上面的代码…

方法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);
}
}

方法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()
);
}
}

方法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');
},
});
}
}

重构方法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,
});
}
}

方法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(),
});
}
}

现在问题是

考虑性能(放在第一位&可读性的下一个)——哪个是最好的选择?

  1. 重构方法1?
  2. 重构方法2?重构方法3?重构方法4?重构方法5?
  3. 原始代码?

我认为最好的方法是数字4,原因如下:

说到可读性,在订阅中传递三个参数(next, error, complete)的方式实际上在RxJS中是不赞成的,因为函数参数可能导致代码难以阅读。你可以在这里阅读更多信息

相反,RxJS建议您使用JS对象作为参数,在其中定义不同回调的代码
({next: () =>{}, error: () =>{}, complete: () =>{})

并且将代码分成函数可以帮助您使其更易于阅读。

如果你传递一个参数(如JS对象)给订阅,RxJS会传递一个空函数给其中一个回调函数,而不是你自己做。

就我个人而言,我会重构成声明式的方法

  1. 创建一个服务来封装所有的数据访问
  2. 在服务中,定义一个变量(而不是方法)来管理从http get返回的Observable。
  3. 在组件中,定义一个变量(不是构造函数或生命周期钩子)来管理从服务
  4. 返回的Observable
  5. 使用模板中的async管道

示例服务:

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() {}
}

示例组件/模板

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) { }
}

有关此声明性模式的更多信息,请参阅:https://youtu.be/0XPxUa8u-LY

最新更新