[英]How do I use .then() to wait for and use the emitted value of a subscription without using await?
I have two methods, the first one subscribes to the value of a service which in turn receives a value from a back-end API.我有两种方法,第一种订阅服务的值,该服务又从后端 API 接收值。 I need to make use of this value in a separate method, so therefore I need to wait for the value of the API to be returned by the first method.
我需要在单独的方法中使用该值,因此我需要等待第一种方法返回 API 的值。
The issue is that I don't want to turn the whole method async by using the await keyword, so instead I figured that making the first method return a promise and then using.then() to await the value would work.问题是我不想通过使用 await 关键字将整个方法变为异步,所以我认为让第一个方法返回 promise 然后使用.then() 来等待该值会起作用。 However when I run my code the console.log is just printing undefined.
但是,当我运行我的代码时,console.log 只是打印未定义。
async determinePreselectedUsers(googleUsers: GoogleUser[]): Promise<any> {
let emails: string[] = [];
googleUsers.forEach(user => {
emails.push(user.email);
});
await this._usersService.determinePreselectedUsers$(emails).subscribe(res => {
return res;
});
}
onOUSelect(selectedOrganisationalUnitPath: string) {
this._usersService.getGoogleUsers$(selectedOrganisationalUnitPath).subscribe((googleUsers: GoogleUser[]) => {
this.determinePreselectedUsers(googleUsers).then( preselectedUsers => {
console.log("Preselected users: ", preselectedUsers); //This is undefined
});
});
}
I assume there's a way to make this work without using await?我认为有一种方法可以在不使用 await 的情况下完成这项工作?
This is not the first time I've seen people use async/await on observable and I wonder where the confusion comes from or even if I'm the one being confused here.这不是我第一次看到人们在 observable 上使用 async/await ,我想知道混淆来自哪里,或者即使我是这里被混淆的人。
Anyway:反正:
There are many things wrong in this single line:这一行有很多问题:
await this._usersService.determinePreselectedUsers$(emails).subscribe(res => {
return res;
});
My guess is that you hope to wait for the subscription to resolve and have the res declared in the scope.我的猜测是您希望等待订阅解决并在 scope 中声明 res。
You'd have to do something like this你必须做这样的事情
obs1.pipe(
switchMap(result1 => fetchSomethingElse(result1))
).subscribe(result2 => console.log(result2));
Which in your snippet would be:您的代码段中将是:
determinePreselectedUsers(googleUsers: GoogleUser[]): Observable<any> {
let emails: string[] = [];
googleUsers.forEach(user => {
emails.push(user.email);
});
return this._usersService.determinePreselectedUsers$(emails);
}
onOUSelect(selectedOrganisationalUnitPath: string) {
this._usersService.getGoogleUsers$(selectedOrganisationalUnitPath).pipe(
switchMap(googleUsers: GoogleUser[]) => this.determinePreselectedUsers(googleUsers)),
}).subscribe(preselectedUsers => {
console.log("Preselected users: ", preselectedUsers); //This is undefined
});
}
determinePreselectedUsers
should return value using resolve
function inside returned Promise
, not return value directly. determinePreselectedUsers
应该在返回Promise
内部使用resolve
function 返回值,而不是直接返回值。
Try this:尝试这个:
determinePreselectedUsers(googleUsers: GoogleUser[]): Promise<any> {
return new Promise((resolve, reject) => {
let emails: string[] = [];
googleUsers.forEach(user => {
emails.push(user.email);
});
this._usersService.determinePreselectedUsers$(emails).subscribe(
// return response in then using resolve
resolve,
// return error in catch using reject
reject
);
});
}
or, You can use toPromise
function of Observable, like:或者,您可以使用 Observable 的
toPromise
function,例如:
determinePreselectedUsers(googleUsers: GoogleUser[]): Promise<any> {
let emails: string[] = [];
googleUsers.forEach(user => {
emails.push(user.email);
});
return this._usersService.determinePreselectedUsers$(emails).toPromise();
}
You can simplify your source code to fewer lines using a map operator and switchMap to switch to another observable.您可以使用map运算符和switchMap将源代码简化为更少的行以切换到另一个 observable。 The key benefit of using Rxjs is that it allows us to write declaratively what the logic does.
使用 Rxjs 的主要好处是它允许我们以声明方式编写逻辑的作用。 Promises are perfectly fine to use, but they describe the resolving of data while reactive programming describes how data flows.
Promise 非常好用,但它们描述了数据的解析,而反应式编程描述了数据的流动方式。
function onOUSelect(selectedOrganisationalUnitPath: string) {
const pluckEmails = users => [users, users.map(user => user.email)];
const handleEmails = ([users, emails]) => this._usersService.determinePreselectedUsers$(users, emails);
this._usersService.getGoogleUsers$(selectedOrganisationalUnitPath).pipe(
map(pluckEmails),
switchMap(handleEmails)
).subscribe(values => console.log(values)); // you must subscribe!
}
The use of async/wait
has some known side effects including error handling, difficulties with concurrency and the fact that it is syntax sugar for writing promises.使用
async/wait
有一些已知的副作用,包括错误处理、并发困难以及它是编写 Promise 的语法糖。 When you use toPromise()
with an observable you inherently change the behavior of how an observable handles errors and empty states.当您将
toPromise()
与 observable 一起使用时,您本质上会改变 observable 如何处理错误和空状态的行为。 There are times when you need to use it, but falling back to toPromise()
so you can continue to work with promises is an anti-pattern in Angular.有时您需要使用它,但回
toPromise()
以便您可以继续使用 Promise 是 Angular 中的反模式。
Observables are the first thing you need to learn in Angular, and the only thing you'll never finish learning. Observables 是你在 Angular 中首先需要学习的东西,也是你唯一永远学不完的东西。
Below should work下面应该工作
determinePreselectedUsers(googleUsers: GoogleUser[]): Observable<any> {
let emails: string[] = [];
googleUsers.forEach(user => {
emails.push(user.email);
});
return this._usersService.determinePreselectedUsers$(emails);
}
onOUSelect(selectedOrganisationalUnitPath: string) {
this._usersService.getGoogleUsers$(selectedOrganisationalUnitPath).subscribe((googleUsers: GoogleUser[]) => {
this.determinePreselectedUsers(googleUsers).then( preselectedUsers => {
console.log("Preselected users: ", preselectedUsers); //This is undefined
});
});
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.