¿Cómo devuelvo la respuesta de una llamada de Observablehttpasync en angular

javascript angular asynchronous typescript observable


Tengo un servicio que devuelve un observable que hace una solicitud http a mi servidor y obtiene los datos. Quiero usar estos datos, pero siempre termino undefined . ¿Cuál es el problema?

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




Answer 1 eko


Reason:

La razón por la que no está undefined es que está realizando una operación asincrónica. Lo que significa que tomará algún tiempo completar el método getEventList (dependiendo principalmente de la velocidad de su red).

Así que veamos la llamada http.

this.es.getEventList()

Después de que realmente haga ("dispare") su solicitud http con subscribe , estará esperando la respuesta. Mientras espera, JavaScript ejecutará las líneas debajo de este código y si encuentra asignaciones / operaciones sincrónicas, las ejecutará de inmediato.

Entonces, después de suscribirse a getEventList() y esperar la respuesta,

console.log(this.myEvents);

la línea se ejecutará de inmediato. Y su valor no está undefined antes de que llegue la respuesta del servidor (o lo que sea que haya inicializado en primer lugar).

Es similar a hacer:

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

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


Solution:

Entonces, ¿cómo superamos este problema? Utilizaremos la función de devolución de llamada, que es el método de subscribe . Porque cuando los datos lleguen del servidor estarán dentro de la subscribe con la respuesta.

Así que cambiando el código a:

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

imprimirá la respuesta ..después de algún tiempo.


Lo que debes hacer:

Puede haber muchas cosas que hacer con su respuesta además de simplemente registrarla; debe realizar todas estas operaciones dentro de la devolución de llamada (dentro de la función de subscribe ), cuando lleguen los datos.

Otra cosa a mencionar es que si usted viene de una Promise de fondo, la then de devolución de llamada corresponde a subscribe con los observables.


Lo que no debes hacer:

No deberías intentar cambiar una operación de sincronización a una operación de sincronización (no es que puedas).Una de las razones por las que tenemos operaciones de sincronización es para no hacer que el usuario espere a que una operación se complete mientras puede hacer otras cosas en ese período de tiempo.Supongamos que una de sus operaciones de sincronización toma 3 minutos para completarse,si no tuviéramos las operaciones de sincronización la interfaz se congelaría por 3 minutos.


Lectura sugerida:

El crédito original a esta respuesta es: ¿Cómo devuelvo la respuesta de una llamada asincrónica?

Pero con el lanzamiento de Angular2 nos introdujeron a la escritura y a los observables,así que esta respuesta esperamos que cubra los fundamentos del manejo de una petición asincrónica con los observables.




Answer 2 RAVI PATEL


Hacer una llamada http en angularjavascript es una operación asíncrona.Así que cuando haces una llamada http se le asigna un nuevo hilo para terminar esta llamada y comenzar la ejecución de la siguiente línea con otro hilo.Es por eso que se obtiene un valor indefinido.Así que haz el siguiente cambio para resolver esto

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



Answer 3 Kliment Ru


Puede usar asyncPype si usa myEvents solo en la plantilla.

Aquí ejemplo con asyncPype y Angular4 HttpClient https://stackblitz.com/edit/angular-rhioqt?file=app%2Fevent.service.ts




Answer 4 Kooldandy


Los observables son perezosos,así que tienes que suscribirte para obtener el valor.Lo suscribiste correctamente en tu código pero simultáneamente registraste la salida fuera del bloque de "suscripción".Por eso es que está "indefinido".

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

  console.log(this.myEvents); //Outside the subscribe block 'Undefined'
}

Así que si lo registras dentro del bloque de suscripción,entonces registrará la respuesta correctamente.

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



Answer 5 Suneet Bansal


Aquí el problema es que está inicializando this.myEvents en subscribe() que es un bloque asincrónico mientras está haciendo console.log() justo fuera del bloque subscribe() . Entonces, se llama a this.myEvents console.log() antes de que this.myEvents se inicialice.

Por favor,mueve tu código console.log()también dentro de subscribe()y listo.

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