简体   繁体   English

如何处理 Angular 8 中的异步 HTTP 调用?

[英]How to handle async HTTP calls in Angular 8?

So I am new to Angular TypeScript and I have a problem.所以我是 Angular TypeScript 的新手,我遇到了问题。

So I have two files here, one is my component file with the function I use on Screen, and second one is HTTP service file where I make calls to a server.所以我这里有两个文件,一个是我在屏幕上使用的带有 function 的组件文件,第二个是 HTTP 服务文件,我在其中调用服务器。

Current my code structure is,目前我的代码结构是,

UserProfileComponent.ts用户配置文件组件.ts

import { Component, OnInit } from '@angular/core';
import { UserService } from 'src/app/services/user.service';

@Component({
  selector: 'app-userprofile',
  templateUrl: './userprofile.component.html',
  styleUrls: ['./userprofile.component.scss']
})
export class UserprofileComponent implements OnInit {

  dataObj: any;

  constructor(private userService: UserService) {
    this.dataObj = this.userService.testCall();
    console.log('dataObj-> ' + JSON.stringify(this.dataObj));
  }

  ngOnInit() {
  }

}

and user.service.ts where I have this calluser.service.ts我有这个电话

  testCall(): any{
    let responseObj: any;
    this.http.get(`${this.baseUrl}/users`).subscribe((data) => {
      console.log('responseObj-> '+JSON.stringify(data));
      responseObj = data;
    });
    return responseObj;
  }

So this issue for me is to handle the async call, the console.log('dataObj-> ' + JSON.stringify(this.dataObj)) does not wait for the service call to end and thus prints undefined .所以对我来说这个问题是处理异步调用, console.log('dataObj-> ' + JSON.stringify(this.dataObj))不会等待服务调用结束,因此打印undefined

I know this is the working but how do I handle this programatically?我知道这是可行的,但我该如何以编程方式处理呢?

I want the response data before I proceed to the next line.在继续下一行之前,我想要响应数据。

Angular CLI: 8.3.25, Node: 12.16.1, OS: win32 x64, Angular: 8.2.14 Angular CLI:8.3.25,节点:12.16.1,操作系统:win32 x64,Angular:8.2.14

The problem is that you do subscribe in your service, but instead you should do it in your component and return Observable from service.问题是您确实subscribe了您的服务,但您应该在您的组件中订阅并从服务中返回Observable

So the final code should look like:所以最终的代码应该是这样的:

testCall(): Observable<UserType[]> {
  //I suppose you return Array of Users
  return this.http.get(`${this.baseUrl}/users`);
}

and component和组件

export class UserprofileComponent implements OnInit {
  dataObj: UserType[];

  constructor(private userService: UserService) {        
  }

  ngOnInit() {
    this.userService.testCall()
      .subscribe((response: UserType[]) => {
        dataObj = response;
        console.log('dataObj-> ' + JSON.stringify(this.dataObj));
      });
  }
}

As @Yury explained, you need to get the subscription to the component level from the service level.正如@Yury 解释的那样,您需要从服务级别获取组件级别的订阅。

To make it even better what you can do is, Create an API service like the following:为了使它更好,你可以做的是,创建一个 API 服务,如下所示:

api.service.ts api.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError, timeout, retry } from 'rxjs/operators';
import { CookieService } from 'ngx-cookie';
import { SERVER } from './static/static.json';

@Injectable({
    providedIn: 'root'
})


export class ApiService {
    user: Observable<any>;
    headers: HttpHeaders;

    constructor(
        private http: HttpClient,
        private cookieService: CookieService
    ) { }
    get(url: string, options?: any) {
        let key = SERVER.api + url;
        this.headers = new HttpHeaders();
        if(typeof options == 'string' && options != " "){
            this.headers = new HttpHeaders().append('Authorization', options);
        }
        return this.http.get(key, {headers: this.headers, withCredentials: false})
        .pipe(
            timeout(15000),
            retry(5),
            catchError(err => throwError(err))
        )
    }
    post(url: string, data: any, options?: any) {
        let key = SERVER.api + url;
        this.headers= new HttpHeaders();

        if(typeof options == 'string' && options != " "){
            this.headers = new HttpHeaders().append('Authorization', options);
        }

        return this.http.post<any>(key , data, {headers: this.headers, withCredentials: false})
        .pipe(
            catchError(err => throwError(err))
        );
    }

    put(url: string, data: any, options?: any) {
        let key = SERVER.api + url;
        this.headers= new HttpHeaders();

        if(typeof options == 'string' && options != " "){
            this.headers = new HttpHeaders().append('Authorization', options);
        }

        return this.http.put<any>(key , data, {headers: this.headers, withCredentials: false})
        .pipe(
            catchError(err => throwError(err))
        );
    }

    delete(url: string, options?: any) {
        let key = SERVER.api + url;
        this.headers= new HttpHeaders();

        if(typeof options == 'string' && options != " "){
            this.headers = new HttpHeaders().append('Authorization', options);
        }

        return this.http.delete<any>(key, {headers: this.headers, withCredentials: false})
        .pipe(
            catchError(err => throwError(err))
        );
    }

}

Then create a Module level service,然后创建一个模块级服务,

abs.service.ts绝对服务.ts

import { Injectable } from '@angular/core';
import { ApiService } from './shared/api.service';
import { AuthService } from './shared/auth.service';
@Injectable({
    providedIn: 'root'
})
export class ABSService {

    constructor(
        private _API: ApiService,
        private _AUTH: AuthService
    ){}
    getUsers(option?) {
        let url = '/users';
        let token;
        if(option){
            url = url + "?" + option;
        }
        if(this._AUTH.loginCheck()){
            token = this._AUTH.getCookie();
        }
        return this._API.get(url, token);
    }

    postUsers(data) {
        let url = '/users';
        let token;
        if(this._AUTH.loginCheck()){
            token = this._AUTH.getCookie();
        }
        return this._API.post(url,data, token);
    }
}

Then you can use this module-level service in the module level component like this:然后您可以在模块级组件中使用此模块级服务,如下所示:

abs.component.ts绝对组件.ts

import { Component, OnInit } from '@angular/core';
import { ABSService } from './abs.service';

@Component({
    selector: 'app-abs',
    templateUrl: './abs.component.html',
    styleUrls: ['./abs.component.css']
})

export class ABSComponent implements OnInit {
    constructor(
        private _API: ABSService
    ) {}
    ngOnInit(){
        this._API.getUsers().subscribe(
            (data:any)=>{
                // something related to data
                this.dataObj = data;
                console.log('dataObj-> ' + JSON.stringify(this.dataObj));
            },
            (err)=>{
                // something related to error
            }
        )
    }
}

I prefer to keep HTTP module separate since the last time when they changed the HTTP module with HttpClient module, I had to go through a lot of work.自从上次他们用 HttpClient 模块更改 HTTP 模块以来,我更喜欢将 HTTP 模块分开,我不得不通过大量工作将 go 模块分开。

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

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