javascript - มีตัวดำเนินการ RXJs ที่ดีกว่าใช้ในสถานการณ์นี้ไหม?
ฉันมีวิธีการให้บริการที่ทำสิ่งต่อไปนี้:
- ค้นหาผู้ใช้จากฐานข้อมูลโดยใช้รหัสของพวกเขา
- ตรวจสอบว่าพบผู้ใช้หรือไม่
- ใช้ bcrypt เพื่อเปรียบเทียบรหัสผ่านที่เก็บไว้ในฐานข้อมูลกับรหัสผ่านที่ให้มาเป็นพารามิเตอร์
- จะโยน UnauthorizedException หากรหัสผ่านไม่ถูกต้อง และจะคืนผู้ใช้หากถูกต้อง
ฉันแค่พยายามหาว่ามีวิธีที่ดีกว่าในการใช้ตัวดำเนินการ RxJS เพื่อทำสิ่งนี้ไหม เพราะฉันไม่ชอบที่ต้องใช้ pipe จาก bcrypt.compare
public validateUser(email: string, pass: string): Promise<UserDto> {
return this.userService
.findOne({ email })
.pipe(
map((user: UserDto) => {
if (!user || !user.password) {
return throwError(new UnauthorizedException());
}
return user;
}),
switchMap((user: UserDto) => {
return from(
bcrypt.compare(pass, user.password) as Promise<boolean>
).pipe(
map((passwordIsCorrect) => ({
passwordIsCorrect,
user
}))
);
}),
switchMap((res) => {
if (!res.passwordIsCorrect) {
return throwError(new UnauthorizedException());
}
return of(res.user);
})
)
.toPromise();
}
คำตอบ #1
ฉันไม่คิดว่าจะมีตัวดำเนินการที่ดีกว่านี้ให้ใช้งาน แต่คุณสามารถทำให้โค้ดง่ายขึ้นโดยให้อยู่ทั้งหมดภายใน switchMap แบบนี้:
public validateUser(email: string, pass: string): Promise<UserDto> {
return this.userService.findOne({ email }).pipe(
switchMap(user => {
if (!user?.password) {
return throwError(new UnauthorizedException());
}
return from(bcrypt.compare(pass, user.password)).pipe(
switchMap(passwordIsCorrect => passwordIsCorrect ? of(user) : throwError(new UnauthorizedException()))
)
})
).toPromise();
}
อย่างไรก็ตาม ในกรณีนี้ ดูเหมือนว่าคุณกำลังพยายามใช้ observables (แปลง promise เป็น observable เพียงเพื่อแปลงกลับเป็น promise)
แม้ว่าฟังก์ชัน userService จะส่งค่า observable กลับมา ทำไมไม่แปลงมันเป็น promise ไปเลยล่ะ? ดูเหมือนว่าโค้ดจะง่ายขึ้นมาก:
public async validateUser(email: string, pass: string): Promise<UserDto> {
const user = await this.userService.findOne({ email }).toPromise();
if (!user?.password || !await bcrypt.compare(pass, user.password)) {
throw new UnauthorizedException();
}
return user;
}
คำตอบ #2
ถ้าคุณไม่ชอบท่อภายในจริง ๆ คุณสามารถใช้ combineLatest เพื่อส่งค่าของ user พร้อมกับ passwordIsCorrect ได้เช่นกัน:
public validateUser(email: string, pass: string): Promise<UserDto> {
return this.userService
.findOne({ email })
.pipe(
map((user: UserDto) => {
if (!user || !user.password) {
return throwError(new UnauthorizedException());
}
return user;
}),
switchMap((user: UserDto) => {
return combineLatest([
from(bcrypt.compare(pass, user.password)),
of(user)
])
}),
map(([passwordIsCorrect, user]) => ({
passwordIsCorrect,
user
})),
switchMap((res) => {
if (!res.passwordIsCorrect) {
return throwError(new UnauthorizedException());
}
return of(res.user);
})
)
.toPromise();
}
