switchMap 运算符不执行返回的可观察对象
switchMap operator doesn't execute the returned observable
我有一个 API (NestJS) 并尝试建立登录。它正在使用 TypeOrm 访问数据库。
当策略 class 调用 auth.validateUser
方法时,我需要从数据库中获取用户并使用 bcrypt
比较密码。问题是 switchMap
没有订阅 returned observable。
这是我的代码:
auth.service.ts
validateUser(email: string, password: string): Observable<User> {
return this.userService.readByEmail(email).pipe(
switchMap(user => {
return new Observable<User>(subscriber => {
if (!user) {
subscriber.next(null)
subscriber.complete()
} else {
bcrypt.compare(password + global.userPepper, user.password)
.then(result => {
const { password, ...validUser } = user
if (result) subscriber.next(validUser as User)
else subscriber.next(null)
subscriber.complete()
})
.catch(err => {
console.log(err)
subscriber.next(null)
subscriber.complete()
})
}
})
})
)
}
user.service.ts
readByEmail(email: string): Observable<User> {
return new Observable<User>(subscriber => {
// This part of the code is never executed
this.userRepo.findOne({ email }).then(user => subscriber.next(user))
})
}
问题是什么,我该如何解决?
更新:
userService.readByEmail
中的问题已根据 Tobias S. 回答中的建议得到解决。
但是来自 authService
的 switchMap
运算符没有被调用。我解决了它改变策略文件,它调用我的 auth.validateUser
到 return 承诺,不再是可观察的并且有效。
local.strategy.ts
之前:
validate(email: string, password: string) {
return this.auth.validateUser(email, password).pipe(
map(user => {
if (!user) {
throw new UnauthorizedException()
}
return user
})
)
}
之后:
validate(email: string, password: string) {
return this.auth.validateUser(email, password).pipe(
map(user => {
if (!user) {
throw new UnauthorizedException()
}
return user
})
).toPromise()
}
我认为这段代码可以进一步简化。你真的不需要用 new Observable()
.
自己创建任何 Observables
在 UserService 中,您可以使用 from
运算符简单地从 Promise 创建一个 Observable。
user.service.ts
readByEmail(email: string): Observable<User> {
return from(this.userRepo.findOne({ email }))
}
在 AuthService 中,如果没有用户,您可以 return EMPTY
然后 return 您正在使用 bcrypt 创建的 Promise。
auth.service.ts
validateUser(email: string, password: string): Observable<User> {
return this.userService.readByEmail(email).pipe(
switchMap(user => {
if (!user) return EMPTY
return bcrypt.compare(password + global.userPepper, user.password)
.then(result => {
const { password, ...validUser } = user
if (result) return validUser as User
})
.catch(console.log)
})
)
}
我有一个 API (NestJS) 并尝试建立登录。它正在使用 TypeOrm 访问数据库。
当策略 class 调用 auth.validateUser
方法时,我需要从数据库中获取用户并使用 bcrypt
比较密码。问题是 switchMap
没有订阅 returned observable。
这是我的代码:
auth.service.ts
validateUser(email: string, password: string): Observable<User> {
return this.userService.readByEmail(email).pipe(
switchMap(user => {
return new Observable<User>(subscriber => {
if (!user) {
subscriber.next(null)
subscriber.complete()
} else {
bcrypt.compare(password + global.userPepper, user.password)
.then(result => {
const { password, ...validUser } = user
if (result) subscriber.next(validUser as User)
else subscriber.next(null)
subscriber.complete()
})
.catch(err => {
console.log(err)
subscriber.next(null)
subscriber.complete()
})
}
})
})
)
}
user.service.ts
readByEmail(email: string): Observable<User> {
return new Observable<User>(subscriber => {
// This part of the code is never executed
this.userRepo.findOne({ email }).then(user => subscriber.next(user))
})
}
问题是什么,我该如何解决?
更新:
userService.readByEmail
中的问题已根据 Tobias S. 回答中的建议得到解决。
但是来自 authService
的 switchMap
运算符没有被调用。我解决了它改变策略文件,它调用我的 auth.validateUser
到 return 承诺,不再是可观察的并且有效。
local.strategy.ts
之前:
validate(email: string, password: string) {
return this.auth.validateUser(email, password).pipe(
map(user => {
if (!user) {
throw new UnauthorizedException()
}
return user
})
)
}
之后:
validate(email: string, password: string) {
return this.auth.validateUser(email, password).pipe(
map(user => {
if (!user) {
throw new UnauthorizedException()
}
return user
})
).toPromise()
}
我认为这段代码可以进一步简化。你真的不需要用 new Observable()
.
在 UserService 中,您可以使用 from
运算符简单地从 Promise 创建一个 Observable。
user.service.ts
readByEmail(email: string): Observable<User> {
return from(this.userRepo.findOne({ email }))
}
在 AuthService 中,如果没有用户,您可以 return EMPTY
然后 return 您正在使用 bcrypt 创建的 Promise。
auth.service.ts
validateUser(email: string, password: string): Observable<User> {
return this.userService.readByEmail(email).pipe(
switchMap(user => {
if (!user) return EMPTY
return bcrypt.compare(password + global.userPepper, user.password)
.then(result => {
const { password, ...validUser } = user
if (result) return validUser as User
})
.catch(console.log)
})
)
}