Bagaimana cara mengembalikan respons dari panggilan Observable / http / async dalam bentuk angular?


110

Saya memiliki layanan yang mengembalikan pengamatan yang melakukan permintaan http ke server saya dan mendapatkan datanya. Saya ingin menggunakan data ini tetapi saya selalu mendapatkannya undefined. Apa masalahnya?

Layanan :

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

Komponen:

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

Saya memeriksa Bagaimana cara mengembalikan respons dari panggilan asinkron? posting tetapi tidak dapat menemukan solusi


2
itu akan menjadi poin yang bagus untuk ditekankan pada fakta bahwa tidak mungkin mengubah operasi asikronus menjadi operasi sinkron.
n00dl3

@ n00dl3 Terima kasih atas tipnya! Saya sudah mencoba menjelaskan di bagian "Apa yang tidak boleh Anda lakukan:". Jangan ragu untuk mengeditnya.
eko


@HereticMonkey posting itu sudah dikreditkan dalam jawaban
eko

@eko Dan? Apakah itu membuat pertanyaan menjadi kurang duplikat?
Monyet Sesat

Jawaban:


117

Alasan:

Alasannya undefinedadalah karena Anda membuat operasi asinkron. Artinya akan membutuhkan waktu untuk menyelesaikan getEventListmetode ini (sebagian besar bergantung pada kecepatan jaringan Anda).

Jadi mari kita lihat panggilan http.

this.es.getEventList()

Setelah Anda benar-benar membuat ("api") permintaan http subscribeAnda dengan Anda akan menunggu respon. Sambil menunggu, javascript akan mengeksekusi baris di bawah kode ini dan jika bertemu dengan tugas / operasi sinkron itu akan segera mengeksekusinya.

Jadi setelah berlangganan getEventList()dan menunggu tanggapannya,

console.log(this.myEvents);

baris akan segera dieksekusi. Dan nilainya adalah undefinedsebelum respons datang dari server (atau ke apa pun yang telah Anda inisialisasi sebelumnya).

Ini mirip dengan melakukan:

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

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


Larutan:

Jadi bagaimana kita mengatasi masalah ini? Kami akan menggunakan fungsi panggilan balik yang merupakan subscribemetode. Karena ketika data datang dari server itu akan berada di dalam subscribedengan respon.

Jadi mengubah kodenya menjadi:

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

akan mencetak tanggapan .. setelah beberapa waktu.


Apa yang harus Anda lakukan:

Mungkin ada banyak hal yang harus dilakukan dengan tanggapan Anda selain hanya mencatatnya; Anda harus melakukan semua operasi ini di dalam callback (di dalam subscribefungsi), saat data tiba.

Hal lain yang perlu disebutkan adalah jika Anda berasal dari Promiselatar belakang, thencallback sesuai subscribedengan observable.


Apa yang tidak boleh Anda lakukan:

Anda tidak boleh mencoba mengubah operasi asinkron menjadi operasi sinkronisasi (Anda tidak bisa). Salah satu alasan kami memiliki operasi asinkron adalah untuk tidak membuat pengguna menunggu operasi selesai sementara mereka dapat melakukan hal lain dalam jangka waktu tersebut. Misalkan salah satu operasi asinkron Anda membutuhkan waktu 3 menit untuk menyelesaikan, jika kami tidak memiliki operasi asinkron, antarmuka akan berhenti selama 3 menit.


Bacaan yang Disarankan:

Kredit asli untuk jawaban ini adalah: Bagaimana cara mengembalikan tanggapan dari panggilan asinkron?

Namun dengan rilis angular2, kami diperkenalkan dengan skrip ketikan dan observable sehingga jawaban ini diharapkan mencakup dasar-dasar penanganan permintaan asinkron dengan observable.


3
Ketika pertanyaan dijawab oleh penanya pada waktu yang sama saat posting .. Ini adalah tempat yang baik untuk berhenti dan menulis posting blog sebagai gantinya
Jonas Praem

3
@JonasPraem Benar, tapi tidak ada salahnya membagi ilmu di Stackoverflow. Seperti yang Anda lihat jumlah suara, itu membantu banyak orang di sini dan akan terus melakukannya.
Amit Chigadani

11

Melakukan panggilan http dalam angular / javascript adalah operasi asinkron. Jadi ketika Anda membuat panggilan http, utas baru akan ditetapkan untuk menyelesaikan panggilan ini dan memulai eksekusi baris berikutnya dengan utas lain. Itulah mengapa Anda mendapatkan nilai yang tidak terdefinisi. jadi buat perubahan di bawah ini untuk mengatasi ini

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


3

Yang bisa diamati itu malas jadi Anda harus berlangganan untuk mendapatkan nilainya. Anda berlangganan dengan benar dalam kode Anda tetapi secara bersamaan mencatat output di luar blok 'berlangganan'. Itulah mengapa ini 'tidak ditentukan'.

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

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

Jadi jika Anda masuk ke dalam blok berlangganan maka itu akan mencatat respons dengan benar.

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

3

Berikut masalah ini, Anda menginisialisasi this.myEventske subscribe()yang merupakan blok asynchronous saat Anda melakukan console.log()hanya keluar dari subscribe()blok. Jadi console.log()dipanggil sebelum this.myEventsdiinisialisasi.

Harap pindahkan kode console.log () Anda juga di dalam subscribe () dan selesai.

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

2

Hasilnya tidak terdefinisi karena proses sudut async. Anda bisa mencoba seperti di bawah ini:

async ngOnInit(){
    const res = await this.es.getEventList();
    console.log(JSON.stringify(res));
}

1

Pastikan juga Anda memetakan respons Anda ke keluaran json. Jika tidak, itu akan mengembalikan teks biasa. Anda melakukannya seperti ini:

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

Tidak ditentukan karena nilai di sini dicatat sebelum data apa pun dari layanan disetel dari panggilan layanan berlangganan di atas. Jadi Anda harus menunggu hingga panggilan ajax selesai dan mengatur data dari data respons.

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

Di sini membuat log Konsol di dalam metode berlangganan yang akan membuat log ketika data diatur dalam variabel myEvents.

ngOnInit(){
    this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
     // This prints the value from the response
    console.log(this.myEvents)
        }); 
  }

0

Anda cukup mencoba metode ini-

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');
    }
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.