¿Cómo devuelvo la respuesta de una llamada Observable/http/async en angular?

Resuelto eko asked hace 7 años • 10 respuestas

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

Servicio :

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

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

Verifiqué ¿Cómo devuelvo la respuesta de una llamada asincrónica? publico pero no pude encontrar una solución

eko avatar Mar 28 '17 03:03 eko
Aceptado

Razón:

La razón undefinedes que estás realizando una operación asincrónica. Lo que significa que llevará algún tiempo completar el getEventListmétodo (dependiendo principalmente de la velocidad de su red).

Así que veamos la llamada http.

this.es.getEventList()

Después de realizar ("disparar") su solicitud http, subscribeestará esperando la respuesta. Mientras espera, JavaScript ejecutará las líneas debajo de este código y, si encuentra asignaciones/operaciones sincrónicas, las ejecutará inmediatamente.

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

console.log(this.myEvents);

La línea se ejecutará inmediatamente. Y su valor es undefinedantes de que llegue la respuesta del servidor (o de lo que sea que lo haya inicializado en primer lugar).

Es similar a hacer:

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

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

**Solución:** > Entonces, ¿cómo superamos este problema? Usaremos la función de devolución de llamada que es el método "suscribir". Porque cuando los datos lleguen del servidor estarán dentro de la "suscripción" con la respuesta.

Entonces 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 un tiempo.


**Qué debes hacer:**

Es posible que haya muchas cosas que hacer con su respuesta además de simplemente registrarla; debes hacer todas estas operaciones dentro de la devolución de llamada (dentro de la subscribefunción), cuando lleguen los datos.

Otra cosa a mencionar es que si tienes antecedentes Promise, la thendevolución de llamada se corresponde subscribecon observables.


**Lo que no debes hacer:**

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


Lectura sugerida:

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

Pero con el lanzamiento de angular2 conocimos el mecanografiado y los observables, por lo que se espera que esta respuesta cubra los conceptos básicos del manejo de una solicitud asincrónica con observables.

eko avatar Mar 27 '2017 20:03 eko

Realizar una llamada http en angular/javascript es una operación asincrónica. Entonces, cuando realice una llamada http, asignará un nuevo hilo para finalizar esta llamada y comenzar la ejecución de la siguiente línea con otro hilo. Es por eso que obtienes un valor indefinido. así que haga el siguiente cambio para resolver esto

this.es.getEventList()  
      .subscribe((response)=>{  
       this.myEvents = response;  
        console.log(this.myEvents); //<-this become synchronous now  
    });
RAVI PATEL avatar May 20 '2017 06:05 RAVI PATEL

Puedes usar asyncPipe si usas myEvents solo en la plantilla.

Aquí ejemplo con asyncPipe y Angular4 HttpClient ejemplo

Kliment Ru avatar Feb 18 '2018 20:02 Kliment Ru

Los observables son vagos, por lo que debes suscribirte para obtener el valor. Lo suscribiste correctamente en tu código pero simultáneamente registraste el resultado fuera del bloque 'suscribir'. Por eso es "indefinido".

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

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

Entonces, si lo registra dentro del bloque de suscripción, registrará la respuesta correctamente.

ngOnInit(){
  this.es.getEventList()
    .subscribe((response)=>{
        this.myEvents = response;
        console.log(this.myEvents); //Inside the subscribe block 'http response'
    });
}
Kooldandy avatar Sep 23 '2018 10:09 Kooldandy

Aquí el problema es que estás inicializando this.myEventsen subscribe()un bloque asíncrono mientras estás console.log()fuera del subscribe()bloque. Entonces console.log(), recibir una llamada antes de this.myEventsque se inicialice.

Mueva su código console.log() también dentro de subscribe() y listo.

ngOnInit(){
    this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
            console.log(this.myEvents);
        });
  }
Suneet Bansal avatar Mar 04 '2019 09:03 Suneet Bansal