错误一:不要将正在处理的逻辑放在tap中
不要将要处理的逻辑放在tap操作符中,并且保持空的订阅以防有很多订阅者
为什么?
tap 运算符主要用于缓存或日志记录等副作用,如果您将逻辑放在那里,每个订阅者都会调用 tap 逻辑,甚至不需要它。但这不是通用规则,它取决于您的用例,如果真的希望所有订阅者都具有此逻辑,或者只有一个订阅者并且想使用“异步管道”,那么则可以这样使用
示例:
tap((data: ObjectType[]) => {
if (!data.every((status) => status.value === "Success")) {
const failed = data.filter(
(status) => status.value !== "Success");
const failedData = failed.reduce((previous, current) => `${previous}${previous.length ? ',' : ''}'${current.personName}'`, );
const reason = data.map((obj) => obj.errorMessage).join('\n');
this.infoService.warn( `Failed uploading data${ failed.length > 1 ? 's' : ''} ${failedData}: Reasons: ${reason}`);
} else {
this.infoService.info(`File${data.length > 1 ? 's' : ''} successfully done`);}
}),
解决方案:
使用subscribe代替tap去处理逻辑
错误二:不要使用常规的error
对于错误处理来说,自带的error仅是错误记录不会抛出错误,只是知道有一些报错且你的observable无法继续执行
// 发出错误
const source = throwError('This is an error!');
// 优雅地处理错误,并返回带有错误信息的 observable
source.subscribe(
val => {console.log(val)},
//只能写成console.error
err => {of(`I caught: ${err}`)}
)
解决方案:
使用rxjs提供的错误处理操作符去处理以及重试逻辑
// 发出错误
const source = throwError('This is an error!');
// 优雅地处理错误,并返回带有错误信息的 observable
source.pipe(catchError(val => of(`I caught: ${val}`))).subscribe(val => console.log(val))
错误三: 不要写三四千行的组件
不要把每件事都放在一个组件中,原因有以下几点:
- 难以去重构
- 对其他开发人员来说可读性较差
- 破坏了组件式开发的规则
解决方案:
始终考虑可复用组件以及父子组件的分离
错误四: 不要在模板中使用大量内联式的代码
- 影响应用的性能
- 将给后续的重构带来困难
示例
@Component({
template: `<p>Welcome {{ fullName() }}</p>`
})
export class PersonComponent{
@Input() person: { firstName: string, lastName: string};
constructor(){}
fullName(){
return this.person..firstName + '' + this.person.lastName
}
}
解决方案
对数据进行计算组合,使用管道提升其稳定性和可复用性
@Component({
template: `<p>Welcome {{ name | nameToString }}</p>`
})
export class PersonComponent{
@Input() person: { firstName: string, lastName: string};
constructor(){}
}
@Pipe({
name: 'nameToString'
})
export class IdPathPipe implement PipeTransform {
transform(value): string {
return value.firstName = value.lastName;
}
}
错误五: 不要使用promise代替observable
如果你将 Promise 与 Angular 组件一起用于 HTTP 请求处理或其他任何事情,你应该考虑这些限制:
- promise不容易取消
- promise不容易重试
不要在订阅中映射或转换数据
假如有很多订阅者需要相同的转换,那么就会造成大量的代码冗余 并且订阅是一个同步调用,我们会被阻塞直到转换完成
示例
this.http.get("https://swapi.dev/api/people/1"
.subscribe(luke => {
name: responese.name,
birthYear: response.birth_year,
height: Number(response.height),
weight: Number(response.weight),
eyeColoe: response.eye_color
})
)
解决方案
您应该使用 Rxjs 映射运算符来预处理您的数据,因为许多订阅者可以获得您的结果,并且您将获得一些代码逻辑(可重用性)。
this.http.get("https://swapi.dev/api/people/1"
.pipe(map(response => ({
name: responese.name,
birthYear: response.birth_year,
height: Number(response.height),
weight: Number(response.weight),
eyeColoe: response.eye_color
}))
.subscribe(luke => {
console.log(luke);
})
)
错误六: 不要把任意module都存放在sharedmodule中
共享模块是一种推荐的angular架构模式,用于组织常用的管道、指令和组件。但是随着应用程序大小的增长,您会发现自己在组件中导入了不需要的依赖项,这会影响您的项目包大小
优化: 在分离出来的文件中定义常量
推荐定义多个组件之间通用的全局常量,当您希望在整个应用程序中使用通用行为时很有用
示例
export class DataTableConstants {
public static ItemPerPage: number = 50;
public static PageSize: number[] = [10, 50, 100, 200, 500];
public static AllowFiltering: boolean = true;
}
import { Component, OnInit } from '@angular/core';
import { DataTableConstants } from './globals/datatable-constants';
@Component({
selector: 'app-example',
templateUrl: './app.example.html',
styleUrls: ['./app.example.css']
})
export class AppExampleComponent implements OnInit{
itemPerPage = DataTableConstants.ItemPerPage;
pageSize = DataTableConstants.PageSize;
allowFiltering = DataTableConstants.AllowFiltering;
ngOnInit() {
console.log(this.itemPerPage);
console.log(this.pageSize);
console.log(this.allowFiltering);
}
}