2017-03-27 57 views
27

我有一個服務,它返回一個對我的服務器執行http請求並獲取數據的observable。我想要使​​用這些數據,但我總是得到undefined。有什麼問題?如何從angular2中的Observable/http/async調用返回響應?

服務

@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({...}) 
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! 
    } 
} 
+0

這將是一個很好的一點是要強調一個事實,這是不可能改造的臺異步操作的synchrnous一。 – n00dl3

+0

@ n00dl3感謝您的提示!我試圖在「你不該做什麼:」部分解釋。隨意編輯它。 – echonax

回答

31

原因:

的原因,它的undefined是,你正在異步操作。這意味着需要一些時間才能完成getEventList方法(主要取決於您的網絡速度)。

所以讓我們來看看http調用。

this.es.getEventList() 

後,你實際上使(「火」)與subscribe您的HTTP請求,你會等待響應。在等待的時候,javascript會執行這段代碼下面的行,如果遇到同步賦值/操作,它會立即執行它們。

於是訂閱了getEventList()並等待響應,之後

console.log(this.myEvents);

線將立即執行。它的值是undefined,在響應從服務器到達之前(或者你首先初始化它的任何東西)。

它類似於這樣:

ngOnInit(){ 
    setTimeout(()=>{ 
     this.myEvents = response; 
    }, 5000); 

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


解決方案:

那麼,我們如何解決這個問題?我們將使用subscribe方法的回調函數。因爲當數據從服務器到達時,它將在響應中位於subscribe之內。

因此改變代碼:一段時間後

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

將打印響應..。


你應該做的:

可能有很多事情要做的不僅僅是記錄它的其他的響應;當數據到達時,您應該在回調(在subscribe函數內)內執行所有這些操作。

另一件要提及的是,如果你來自Promise背景,then回調對應於subscribe與observables。


你不應該做的:

你不應該試圖改變一個異步操作同步操作(不是說你可以)。我們進行異步操作的原因之一是不會讓用戶等待操作完成,而他們可以在該時間段內完成其他操作。假設你的一個異步操作需要3分鐘才能完成,如果我們沒有異步操作,界面會在3分鐘內凍結。


推薦閱讀:

原來的信用這個答案去:How do I return the response from an asynchronous call?

但隨着angular2釋放我們被介紹給打字稿及觀測所以這個答案有望覆蓋的基礎知識用observables處理異步請求。

0

還確保您將響應映射到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

使在角/ javascript中的HTTP調用是異步操作。 因此,當你進行http調用時,它會分配新的線程來完成這個調用,並開始執行另一個線程的下一行。 這就是爲什麼你得到未定義的價值。 所以要低於變化來解決這個

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

你可以簡單地嘗試這種方法 -

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