角度可观察的返回未定义结果

时间:2020-05-16 06:35:19

标签: javascript angular typescript ionic-framework angular-observable

我有将用户令牌传递给服务器并将结果返回给组件的服务,但是当我的令牌存在时,它将不断返回token: undefined

代码

注意:我对每个部分都进行了评论,以更好地理解。

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);
        }
      });
    }
}

您知道如何解决此问题吗?

4 个答案:

答案 0 :(得分:1)

您可以使用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));
      })
    );
  }
}

答案 1 :(得分:0)

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

此呼叫是异步的,您不会在下一行获得令牌 像这样尝试

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;

    }
}

答案 2 :(得分:0)

在发出http请求之前,您需要等待promise返回一个值。您可以将令牌逻辑放入返回承诺的自己的函数中,然后使用RxJS from函数启动可观察对象。一旦承诺返回值,您就可以使用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));
  }
}

答案 3 :(得分:0)

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

    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并添加到Promise()返回行)

您可以调用如下方法。

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,然后从该函数返回令牌)