您可以在流中的任何位置抛出错误。如果results.data 不包含传入guildId 的Guild,则以下sn-p 将引发错误。现在您的结果将被定义(非空/未定义)或错误;
public getGuild(guildId: string, token: string): Observable<Guild> {
return this.httpService.get<Guild[]>(url, {
headers: { authorization: token },
}).pipe(
map(result =>
result.data.find(guild => guild.id === guildId)
),
tap(guild => {
if(guild == null) throw new Error(`No guild with ${guildId} found`);
})
);
}
惯用的 RxJS
tap 接受一个流并原样返回相同的流。它可以被视为与 map(x => x) 相同 - 有些人认为惯用的 RxJS 应该排除 tap 在程序中拥有任何控制流。
这通常适用于用户想要设置全局变量,然后稍后根据该值做出选择的情况。
from(something).pipe(
tap(x => {
if(x < 10) this.globalValue = 0;
if(x > 9) this.globalValue = 25;
else this.globalValue = 75;
}),
mergeMap(x => this.service.save(x, this.globalValue))
);
在这种情况下,您的流不再是“纯”的,因为您无法具体推断this.globalValue 将是什么(也许其他一些代码块在您阅读它之前再次更改了这个全局值)。这使得事情很难测试。你失去了 RxJS 函数式风格的许多好处。
如果您将tap(x => doSomething) 替换为map(x => {doSomething; return x}),所有这些问题都是相同的——它们是同一组问题。然而,习惯上,程序员可能会花更多时间了解map 正在做什么,因为他们可能认为tap 没有控制流。
主观部分
在我看来,tap 是一个抛出错误的好地方。它应该告诉任何阅读/更新代码的开发人员“此错误是由流中此点的值的形状产生的”。验证和日志记录之类的东西非常适合(惯用的)RxJS 的tap 运算符。在验证期间抛出错误是很自然的。
您将如何编写自定义断言运算符(您可以将它们全部剥离以用于生产构建,而不必担心会破坏任何东西)
function assert<T>(fn: (x: T) => boolean): MonoTypeOperatorFunction<T>{
return s => s.pipe(
tap(val => {
if(!fn(val)) throw new Error("Assertion Failed");
})
);
}
使用tap 的实现在清晰性方面非常突出。由于tap这个词没有出现在您的信息流中,因此您在使用过程中也不会遇到任何惯用问题。
public getGuild(guildId: string, token: string): Observable<Guild> {
return this.httpService.get<Guild[]>(url, {
headers: { authorization: token },
}).pipe(
map(result =>
result.data.find(guild => guild.id === guildId)
),
assert(result => result != null)
);
}
这很清楚,我会说。不过,我们可以处理更好的错误消息。
另一种避免争论的方法
如果你不想那样使用tap,这里有另一种用相当惯用的 RxJS 编写它的方法。
public getGuild(guildId: string, token: string): Observable<Guild> {
return this.httpService.get<Guild[]>(url, {
headers: { authorization: token },
}).pipe(
map(result => {
const guild = result.data.find(guild => guild.id === guildId);
if(guild == null) throw new Error(`No guild with ${guildId} found`);
return guild;
})
);
}
现在 - 错误被抛出为“我未能将结果:Guild[] 映射到 guild:Guild”错误。