简体   繁体   English

如何让 async/await 等待 Observable 返回

[英]How to make async/await wait for an Observable to return

Fairly new to Angular, and struggling with Promises, Observables and async/await.对 Angular 来说相当新,并且在 Promises、Observables 和 async/await 上苦苦挣扎。

  • I have a function which needs the current user details to do some tasks.我有一个 function 需要当前用户详细信息来执行一些任务。
  • For this, I wrote a fetch user detail method which returns a promise and the tasks are handled within the 'then' part.为此,我编写了一个获取用户详细信息的方法,该方法返回 promise,并且任务在“then”部分中处理。
  • The fetch method itself calls another method which invokes the http.get to get the user details from database, and returns an Observable. fetch 方法本身调用另一个方法,该方法调用 http.get 从数据库中获取用户详细信息,并返回一个 Observable。
  • I used async/await here for the function to wait for http.get to return.我在这里使用 async/await 来让 function 等待 http.get 返回。

However, this doesn't seem to work.但是,这似乎不起作用。 I have a feeling this has something to do with how Observables/subscribe works, but I am unable to solve it.我觉得这与 Observables/subscribe 的工作方式有关,但我无法解决它。

Code snippet:代码片段:

    initPage() {
      fetchCurrentUserDetails().then((user) => { //tasks dependent on current user
        //task 1
        //task 2
      });
    }

    fetchCurrentUserDetails(): Promise<any> {
      return Promise.resolve((async () => {
        let currentUser = this.global.getUser();// check if user is defined already
        let userId: string = sessionStorage.getItem('userid');

        if (currentUser == undefined) {
          let initProfile = new Promise(resolve => resolve(this.fetchDetailsFromDB(userId)));
          const profile: any = await initProfile; //Waits, but returns before the Observable comes back

          let user = new User();
          // initialize user with the fetched values
          user.id = profile.id; // Undefined, since value not returned yet
          user.name = profile.user_name; // Undefined, since value not returned yet
          // Set this user in a global variable
          this.global.setUser(user);
       }

       return this.global.getUser();
      })());
    }

    fetchDetailsFromDB(userId: string) {
      //callProfileService has nothing but the http.get statement
      this.callProfileService(userId).subscribe((response) => {
        let profile = response.body.response.data.user;
         return profile;
      });
    }


Edit: adding how I tried with toPromise:编辑:添加我如何尝试使用 toPromise:

    fetchDetailsFromDB(userId: string) {
      this.callUserProfileService(userId).toPromise().then((response) => {
       let profile = response.body.response.data.user;
       return profile;
    });

Is this the right way to do this?这是正确的方法吗? If so, how to make the await wait for the Observable to return?如果是这样,如何让 await 等待 Observable 返回?

Indeed, you need the toPromise() method, but don't forget to return that promise (the return in the callback is not enough -- the function fetchDetailsFromDB needs to return a promise).实际上,您需要toPromise()方法,但不要忘记返回promise (回调中的return是不够的 - function fetchDetailsFromDB需要返回一个承诺)。

On the rest of your code: it is an antipattern to use Promise.resolve and new Promise like that: as a rule of thumb, don't create a new promise with either of these when you already have a promise to work with (eg from an API function call). On the rest of your code: it is an antipattern to use Promise.resolve and new Promise like that: as a rule of thumb, don't create a new promise with either of these when you already have a promise to work with (eg来自 API function 调用)。

So here is how you could do it with async methods:因此,这是使用async方法的方法:

async fetchCurrentUserDetails(): Promise<any> {
//^^^^
    let currentUser = this.global.getUser();
    if (currentUser == undefined) {
      const userId: string = sessionStorage.getItem('userid');
      const profile: any = await this.fetchDetailsFromDB(userId);
      currentUser = new User();
      currentUser.id = profile.id;
      currentUser.name = profile.user_name;
      this.global.setUser(currentUser);
   }
   return currentUser;
}

async fetchDetailsFromDB(userId: string): Promise<any> {
   const response = await this.callUserProfileService(userId).toPromise();
   return response.body.response.data.user;
};

you can use callback你可以使用回调

initPage() {
    fetchCurrentUserDetails((user) => {
        //task 1
        //task 2
    });
}

fetchCurrentUserDetails(callback) {
    const currentUser = this.global.getUser();

    if (!currentUser) {
        const userId: string = sessionStorage.getItem('userid');
        return this.callProfileService(userId).subscribe((response) => {
            const profile = response.body.response.data.user;
            let user = new User();
            user.id = profile.id;
            user.name = profile.user_name;
            this.global.setUser(user);
            return callback(user);
        });
    } else {
        return callback(currentUser);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM