2017-03-27 20 views
27

मेरे पास ऐसी सेवा है जो एक अवलोकन योग्य लौटाती है जो मेरे सर्वर पर http अनुरोध करता है और डेटा प्राप्त करता है। मैं इस डेटा का उपयोग करना चाहता हूं लेकिन मैं हमेशा undefined प्राप्त करना समाप्त करता हूं। समस्या क्या है?मैं कोणीय/http/async कॉल से angular2 में प्रतिक्रिया कैसे वापस कर सकता हूं?

सेवा:

@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 अनुरोध करें कि आप प्रतिक्रिया की प्रतीक्षा करने हो जाएगा। प्रतीक्षा करते समय, जावास्क्रिप्ट इस कोड के नीचे की रेखाओं को निष्पादित करेगा और यदि यह सिंक्रोनस असाइनमेंट/ऑपरेशंस का सामना करता है तो यह तुरंत उन्हें निष्पादित करेगा।

तो 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 से अवलोकन के साथ मेल खाता है।


तुम क्या नहीं करना चाहिए:

आप एक समन्वयन कार्रवाई करने के लिए एक async आपरेशन को बदलने की कोशिश नहीं करनी चाहिए (आप कर सकते हैं कि नहीं)। हमारे पास एसिंक ऑपरेशंस होने के कारणों में से एक यह है कि उपयोगकर्ता उस ऑपरेशन को पूरा करने के लिए इंतजार नहीं कर रहा है, जबकि वे उस समय की अन्य चीजें कर सकते हैं। मान लीजिए कि आपके एसिंक ऑपरेशंस में से एक को पूरा करने में 3 मिनट लगते हैं, अगर हमारे पास एसिंक ऑपरेशंस नहीं था तो इंटरफ़ेस 3 मिनट तक जम जाएगा।


सुझाए गए पढ़ना:

इस उत्तर के लिए मूल क्रेडिट को जाता है: How do I return the response from an asynchronous call?

लेकिन angular2 रिलीज के साथ हम टाइपप्रति लिए पेश किए गए और observables तो यह जवाब उम्मीद है कि बुनियादी बातों को शामिल किया गया की अवलोकन के साथ एक एसिंक्रोनस अनुरोध को संभालने।

0

यह भी सुनिश्चित करें कि आप एक जेसन आउटपुट पर अपनी प्रतिक्रिया को मैप करें। अन्यथा यह सादे पाठ वापस कर देगा। आप इस तरह ऐसा करते हैं:

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

कोणीय/जावास्क्रिप्ट में एक http कॉल करना अतुल्यकालिक ऑपरेशन है। तो जब आप http कॉल करते हैं तो यह इस कॉल को समाप्त करने के लिए नया थ्रेड असाइन करेगा और अगली पंक्ति को अन्य थ्रेड के साथ निष्पादन शुरू करेगा। यही कारण है कि आपको अपरिभाषित मूल्य मिल रहा है। तो यह

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

आप बस इस method-

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

कोशिश कर सकते हैं आप asyncPype उपयोग कर सकते हैं अगर आप केवल टेम्पलेट में myEvents का उपयोग को हल करने परिवर्तन नीचे हैं।

यहाँ asyncPype साथ उदाहरण और Angular4 HttpClient https://stackblitz.com/edit/angular-rhioqt?file=app%2Fevent.service.ts

संबंधित मुद्दे