简体   繁体   English

如何在不使用 await 的情况下使用 .then() 等待并使用订阅的发出值?

[英]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;
});
  • you are using await with a subscription object您正在使用 await 订阅 object
  • your observable seems to be a function which has the same name as the function you are calling this with (minus the $)您的 observable 似乎是 function 与 function 同名(减去 $)
  • your callback in subscribe doesn't do anything.您在订阅中的回调没有做任何事情。

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.

相关问题 如何在不使用异步等待的情况下以角度获取订阅内的价值 - How to get value inside the subscription in angular without using async await 如何使用 2 个 observable 发出的值作为 http 请求的参数,其中 1 个 observable 将另一个重置为默认值? - How do I use values emitted by 2 observables as parameters to an http request, with 1 observable resetting the other to a default value? Angular 如何将 await 与 .subscribe 一起使用 - Angular how do I use await with .subscribe 对订阅使用异步等待 - use async-await with subscription 如何在 Array.prototype.map 中使用 await 等待 RxJS Observables - How to use await in Array.prototype.map to wait for RxJS Observables 如何使用数组的索引值并将其传递给HTML模态,这样我就可以在那里显示数据而无需在angular 7中使用循环 - How do I use the index value of an array and pass it to a HTML modal so I can show the data there without using a loop in angular 7 订阅后调用 next 时,如何获取订阅中 Observable 的最后发出值? - How to get last emitted value of on Observable in the subscription when next is called after the subscription? 如何使用变量作为 ngClass 的值? - how do I use a variable for the value of ngClass? 在 Observable 上使用 await 时,我应该使用什么来代替 toPromise()? - What should I use instead of toPromise() when using await on an Observable? 如何在第一个正在运行的订阅中以角度 6 同步使用第二个订阅返回值? - How to use second subscription return value in first's running subscription in sync in angular 6?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM