首页 文章

如何从angular2中的Observable / http / async调用返回响应?

提问于
浏览
52

我有一个服务,它返回一个observable,它向我的服务器发送一个http请求并获取数据 . 我想使用这些数据,但我总是得到 undefined . 有什么问题?

Service

@Injectable()
export class EventService {

  constructor(private http: Http) { }

  getEventList(): Observable<any>{
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });

    return this.http.get("http://localhost:9999/events/get", options)
                .map((res)=> res.json())
                .catch((err)=> err)
  }
}

Component:

@Component({...})
export class EventComponent {

  myEvents: any;

  constructor( private es: EventService ) { }

  ngOnInit(){
    this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
        });

    console.log(this.myEvents); //This prints undefined!
  }
}

6 回答

  • 0

    Reason:

    它是 undefined 的原因是你正在进行异步操作 . 这意味着完成 getEventList 方法需要一些时间(主要取决于您的网络速度) .

    所以让我们来看看http调用 .

    this.es.getEventList()
    

    在您使用 subscribe 实际创建("fire")http请求后,响应将为 waiting . 在等待时,javascript将执行此代码下面的行,如果遇到同步赋值/操作,它将立即执行它们 .

    所以在订阅 getEventList() 并等待响应后,

    console.log(this.myEvents);

    线将立即执行 . 并且在响应从服务器到达之前它的值是 undefined (或者首先是你初始化它的任何东西) .

    它类似于:

    ngOnInit(){
        setTimeout(()=>{
            this.myEvents = response;
        }, 5000);
    
        console.log(this.myEvents); //This prints undefined!
    }
    

    Solution:

    那么我们如何克服这个问题呢?我们将使用回调函数,即subscribe方法 . 因为当数据从服务器到达时,它将在订阅中包含响应 .

    所以将代码更改为:

    this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
            console.log(this.myEvents); //<-- not undefined anymore
        });
    

    将在一段时间后打印回复 .


    What you should do:

    除了记录之外,您的响应可能还有很多事情要做;当数据到达时,你应该在回调内部(在 subscribe 函数内)完成所有这些操作 .

    另一件需要提及的是,如果你来自 Promise 背景, then 回调对应于带有observables的 subscribe .


    What you shouldn't do:

    您不应该尝试将异步操作更改为同步操作(不是您可以) . 我们进行异步操作的原因之一是不让用户等待操作完成,而他们可以在该时间段内执行其他操作 . 假设您的一个异步操作需要3分钟才能完成,如果我们没有异步操作,则接口将冻结3分钟 .


    Suggested Reading:

    这个答案最初归功于:How do I return the response from an asynchronous call?

    但是对于angular2版本,我们被引入了typescript和observables,所以这个答案希望涵盖处理带有observables的异步请求的基础知识 .

  • 0

    在angular / javascript中进行http调用是异步操作 . 因此,当您进行http调用时,它将分配新线程来完成此调用并开始执行下一行与另一个线程 . 这就是为什么你得到未定义的 Value . 所以在下面进行更改以解决此问题

    this.es.getEventList()  
          .subscribe((response)=>{  
           this.myEvents = response;  
            console.log(this.myEvents); //<-this become synchronous now  
        });
    
  • 5

    如果仅在模板中使用myEvents,则可以使用asyncPype .

    这里用asyncPype和Angular4的示例HttpClient https://stackblitz.com/edit/angular-rhioqt?file=app%2Fevent.service.ts

  • 63

    还要确保将响应映射到json输出 . 否则它将返回纯文本 . 你这样做:

    getEventList(): Observable<any>{
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });
    
    return this.http.get("http://localhost:9999/events/get", options)
                .map((res)=>{ return res.json();}) <!-- add call to json here
                .catch((err)=>{return err;})
    

    }

  • -1

    Observable是懒惰的,所以你必须订阅才能获得 Value . 您在代码中正确订阅了它,但同时将输出记录在'subscribe'块之外 . 这就是“未定义”的原因 .

    ngOnInit() {
      this.es.getEventList()
        .subscribe((response) => {
            this.myEvents = response;
        });
    
      console.log(this.myEvents); //Outside the subscribe block 'Undefined'
    }
    

    因此,如果您将其记录在订阅块中,那么它将正确记录响应 .

    ngOnInit(){
      this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
            console.log(this.myEvents); //Inside the subscribe block 'http response'
        });
    }
    
  • 1

    你可以试试这个方法 -

    let headers = new Headers({'Accept': 'application/json'});
    let options = new RequestOptions({headers: headers});
    
    return this.http
        .get(this.yourSearchUrlHere, options) // the URL which you have defined
        .map((res) => {
            res.json(); // using return res.json() will throw error
        }
        .catch(err) => {
            console.error('error');
        }
    

相关问题