Come posso restituire la risposta da una chiamata Observable / http / async in angular2?

Ho un servizio che restituisce un osservabile che fa una richiesta http al mio server e ottiene i dati. Voglio usare questi dati ma finisco sempre per diventare undefined . Qual è il problema?

Servizio :

 @Injectable() export class EventService { constructor(private http: Http) { } getEventList(): Observable{ 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) } } 

Componente:

 @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! } } 

Ragionare:

Il motivo per cui non è undefined è che stai eseguendo un’operazione asincrona. Significa che ci vorrà del tempo per completare il metodo getEventList (dipende in gran parte dalla velocità della tua rete).

Quindi guardiamo la chiamata http.

 this.es.getEventList() 

Dopo aver effettivamente fatto (“licenziare”) la tua richiesta http con subscribe , attendi la risposta. Durante l’attesa, javascript eseguirà le linee sotto questo codice e se incontra assegnazioni / operazioni sincrone verrà eseguito immediatamente.

Quindi, dopo esserti iscritto a getEventList() e aver atteso la risposta,

console.log(this.myEvents);

linea verrà eseguita immediatamente. E il valore di esso undefined è undefined prima che la risposta arrivi dal server (o da qualunque cosa l’abbia inizializzata in primo luogo).

È simile a fare:

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


Soluzione:

Quindi, come superiamo questo problema? Useremo la funzione di callback che è il metodo di subscribe . Perché quando i dati arrivano dal server sarà all’interno della subscribe con la risposta.

Quindi, cambiando il codice in:

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

stamperà la risposta .. dopo un po 'di tempo.


Cosa dovresti fare:

Ci potrebbero essere molte cose da fare con la tua risposta oltre alla semplice registrazione; dovresti fare tutte queste operazioni all'interno del callback (all'interno della funzione subscribe ), quando arrivano i dati.

Un'altra cosa da ricordare è che se vieni da uno sfondo di Promise , il callback corrisponde a subscribe con osservabili.


Cosa non dovresti fare:

Non dovresti provare a cambiare un'operazione asincrona con un'operazione di sincronizzazione (non che tu possa farlo). Uno dei motivi per cui abbiamo operazioni asincrone è quello di non aspettare che l'operazione venga completata mentre possono fare altre cose in quel periodo di tempo. Supponiamo che una delle operazioni asincrone impieghi 3 minuti per essere completata, se non avessimo le operazioni asincrone l'interfaccia si congelerebbe per 3 minuti.


Lettura suggerita:

Il credito originale per questa risposta va a: Come restituisco la risposta da una chiamata asincrona?

Ma con la release angular2 siamo stati introdotti a typescript e osservabili, quindi questa risposta si spera copra le basi del trattamento di una richiesta asincrona con osservabili.

Effettuare una chiamata http in angular / javascript è un’operazione asincrona. Quindi, quando effettui la chiamata http, assegnerà un nuovo thread per terminare questa chiamata e avvierà l’esecuzione della riga successiva con un altro thread. Questo è il motivo per cui ottieni un valore indefinito. quindi fai sotto cambia per risolvere questo

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

assicurati anche di mappare la tua risposta a un output JSON. Altrimenti restituirà il testo normale. Lo fai in questo modo:

 getEventList(): Observable{ 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();}) 

È ansible utilizzare asyncPype se si utilizzano myEvents solo nel modello.

Qui esempio con asyncPype e Angular4 HttpClient https://stackblitz.com/edit/angular-rhioqt?file=app%2Fevent.service.ts

Puoi semplicemente provare questo metodo-

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