Angular 可观察到 return 未定义的结果

Angular observable return undefined results

我有一个服务,我将用户令牌传递给服务器并将 return 结果传递给组件,但是当我的令牌存在时它保持 returning token: undefined

代码

Note: I commented each part for better understanding.

Service

export class GroupsService {

    token: any;

    constructor(
        private storageIonic: NativeStorage,
        private env: EnvService,
        private http: HttpClient,
    ) {
        // Get token
        this.storageIonic.getItem('token').then((token) => {
        this.token = token.access_token;
        }).catch(error => console.error(error));
    }

    getGroups(): Observable<any> {
        // I also add this here to make sure that i will get token in any case, yet it's returning undefined
        if (this.token === undefined) {
        this.storageIonic.getItem('token').then((token) => {
            this.token = token.access_token;
        }).catch(error => console.error(error));
        }

        console.log('token: ', this.token);  // undefined
        const httpOptions = {
        headers: new HttpHeaders({
            Authorization : this.token,  //sending token to server
            Accept: 'application/json, text/plain',
            'Content-Type': 'application/json'
        })
        };
        return this.http.get(`${this.env.GROUPS}`, httpOptions).pipe(
        map(groups => groups)
        );
    }
}

Component

export class Tab1Page implements OnInit {

    groups: any[] = [];
    groupsOpts = {
      loop: false,
      slidesPerView: 3,
      slidesPerColumn: 2
    };

    constructor(
      private groupsService: GroupsService,
      private menu: MenuController,
    ) {
      this.menu.enable(true);
      this.getGroups();
    }

    ngOnInit() {
      //
    }
    // I added async/await yet result hasn't change.
    async getGroups() {
      await this.groupsService.getGroups().subscribe((res) => {
        console.log('res: ', res);
        console.log('res data: ', res.data);
        console.log('res data data: ', res.data.data);
        for (const group of res.data) {
          this.groups.push(group);
        }
      });
    }
}

知道如何解决这个问题吗?

 this.storageIonic.getItem('token').then((token) => {
            this.token = token.access_token;
        }).catch(error => console.error(error));
 }

这个调用是异步的,你不会在下一行得到token 试试这个

export class GroupsService {

    token: any;

    constructor(
        private storageIonic: NativeStorage,
        private env: EnvService,
        private http: HttpClient,
    ) {
        // Get token
        this.storageIonic.getItem('token').then((token) => {
            this.token = token.access_token;
        }).catch(error => console.error(error));
    }

    getGroups(): Observable < any > {
        // I also add this here to make sure that i will get token in any case, yet it's returning undefined
        let response = new Observable<any>();
        if (this.token === undefined) {
            this.storageIonic.getItem('token').then((token) => {
                this.token = token.access_token;

                console.log('token: ', this.token); // undefined
                const httpOptions = {
                    headers: new HttpHeaders({
                        Authorization: this.token, //sending token to server
                        Accept: 'application/json, text/plain',
                        'Content-Type': 'application/json'
                    })
                };
                response = this.http.get(`${this.env.GROUPS}`, httpOptions).pipe(
                    map(groups => groups)
                );
            }).catch(error => console.error(error));
        }

        return response;

    }
}

您可以使用 switchMap 来传输令牌承诺数据。

import { from } from "rxjs";

export class GroupsService {
  token: any;
  getGroups(): Observable<any> {
    // I also add this here to make sure that i will get token in any case, yet it's returning undefined
    const tokenPromise =
      this.token === undefined
        ? this.storageIonic.getItem("token")
        : Promise.resolve(this.token);

    return from(tokenPromise).pipe(
      switchMap((token) => {
        this.token = token;
        const httpOptions = {
          headers: new HttpHeaders({
            Authorization: this.token, //sending token to server
            Accept: "application/json, text/plain",
            "Content-Type": "application/json",
          }),
        };
        return this.http
          .get(`${this.env.GROUPS}`, httpOptions)
          .pipe(map((groups) => groups));
      })
    );
  }
}

在发出 http 请求之前,您需要等待 return 一个值的承诺。您可以将令牌逻辑放入 return 承诺的函数中,然后使用 RxJS from 函数启动可观察对象。一旦承诺 return 成为一个值,您就可以使用 switchMap 发出您的 http 请求。

我已经将你的 map 包含在 RxJS 管道中,尽管它目前什么也没做。

export class GroupsService {

  token: any;

  constructor(
    private storageIonic: NativeStorage,
    private env: EnvService,
    private http: HttpClient,
  ) {
  }

  getGroups(): Observable<any> {
    return from(this.getToken()).pipe(
      switchMap(() => {
        const httpOptions = {
          headers: new HttpHeaders({
            Authorization : this.token,  //sending token to server
            Accept: 'application/json, text/plain',
            'Content-Type': 'application/json'
          })
        };

        return this.http.get(`${this.env.GROUPS}`, httpOptions);
      }),
      map(groups => groups)
    );          
  }

  private getToken(): Promise<any> {
    if (this.token) {
      return new Promise((resolve, reject) => resolve(this.token));    
    }

    return this.storageIonic.getItem('token')
      .then((token) => {
          this.token = token.access_token;
      }).catch(error => console.error(error));
  }
}

我不确定您问题的根源,但您可能希望将您的可观察对象更改为承诺,正如我在评论中所解释的那样。

    getGroups(): Promise<any> {
        // I also add this here to make sure that i will get token in any case, yet it's returning undefined
        if (this.token === undefined) {
        this.storageIonic.getItem('token').then((token) => {
            this.token = token.access_token;
        }).catch(error => console.error(error));
        }

        console.log('token: ', this.token);  // undefined
        const httpOptions = {
        headers: new HttpHeaders({
            Authorization : this.token,  //sending token to server
            Accept: 'application/json, text/plain',
            'Content-Type': 'application/json'
        })
        };
        return this.http.get(`${this.env.GROUPS}`, httpOptions).toPromise();
        // Also probably the below one works too, you can try to find the proper syntax, it was something like this
        return this.http.get(`${this.env.GROUPS}`, httpOptions).pipe(
        map(groups => groups)
        ).toPromise();
    }

我改了一些台词。 (更改方法签名,Observable => Promise 并将 toPromise() 添加到 return 行)

您可以像下面这样调用方法。

const response = await getGroups(); // This one will return the response of the request. 
If you debug the code you will see that your code will wait here until it gets a response.

// IF YOU DO LIKE BELOW IT WON'T MAKE ANY SENSE
const response = getGroups(); // This will not make the call, it will just return the request object.
// In order to do the operation defined in a promise, you must call it with await prefix.

您可能还需要将上述解决方案应用于代码的其他部分。例如。您正在构造函数下初始化令牌,据我所知这不是一个好习惯,您可能希望将该初始化移动到 onInit() 下并使 onInit 函数异步。通过这种方式,您可以确保在进行调用时定义了令牌,否则在发出请求时您的令牌可能无法初始化。而且由于您没有在未定义检查中等待您的代码,所以同样的事情会再次发生。 (将您的 storageIonic.getItem(token: string) 函数转换为 promise 和 return 来自该函数的令牌)