Bir Observable / http / async çağrısının yanıtını açısal olarak nasıl döndürürüm?


110

Sunucuma bir http isteği yapan ve verileri alan bir gözlemlenebilir olanı döndüren hizmetim var. Bu verileri kullanmak istiyorum ama her zaman elde ederim undefined. Sorun ne?

Hizmet :

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

Bileşen:

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

Kontrol ettim Eşzamansız bir aramadan gelen yanıtı nasıl geri getirebilirim? gönder ama bir çözüm bulamadım


2
bu, eşzamanlı olmayan bir işlemi eşzamanlı bir işleme dönüştürmenin mümkün olmadığı gerçeğini vurgulamak için iyi bir nokta olacaktır.
n00dl3

@ n00dl3 İpucu için teşekkürler! "Yapmamanız gerekenler:" bölümünde açıklamaya çalıştım. Düzenlemekten çekinmeyin.
eko


@HereticMonkey bu gönderi cevapta zaten yer alıyor
eko

@eko Ve? Bu, soruyu bir kopya olmaktan çıkarıyor mu?
Heretic Maymun

Yanıtlar:


117

Sebep:

Bunun nedeni, undefinedeşzamansız bir işlem yapıyor olmanızdır. Bu, getEventListyöntemi tamamlamanın biraz zaman alacağı anlamına gelir (çoğunlukla ağ hızınıza bağlı olarak).

Öyleyse http çağrısına bakalım.

this.es.getEventList()

Siz gerçekten ("ateş") yaptıktan sonra http talebiniz yanıt bekliyorsubscribe olacak . Javascript beklerken bu kodun altındaki satırları çalıştıracak ve eşzamanlı atamalarla / işlemlerle karşılaşırsa hemen çalıştıracaktır.

Yani, abone olduktan getEventList()ve yanıtı bekledikten sonra ,

console.log(this.myEvents);

satır hemen çalıştırılacaktır. Ve değeri undefined, sunucudan yanıt gelmeden öncedir (ya da ilk başta onu başlattığınız her şeye).

Yapmaya benzer:

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

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


Çözüm:

Peki bu sorunu nasıl aşarız? subscribeYöntem olan geri arama işlevini kullanacağız . Çünkü veriler sunucudan geldiğinde subscribeyanıtı ile birlikte olacaktır .

Yani kodu şu şekilde değiştirmek:

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

yanıtı yazdıracak .. bir süre sonra.


Ne yapmalısın:

Yanıtınız ile günlük tutmak dışında yapılacak birçok şey olabilir; subscribeveri geldiğinde tüm bu işlemleri geri arama içinde ( işlevin içinde ) yapmanız gerekir .

Söylenecek başka bir şey de, bir Promisearka plandan geliyorsanız , thengeri subscribearamanın gözlemlenebilirlere karşılık gelmesidir.


Yapmamanız gerekenler:

Eşzamanlı olmayan bir işlemi eşitleme işlemine değiştirmeye çalışmamalısınız (yapabileceğinizden değil). Eşzamansız işlemlere sahip olmamızın nedenlerinden biri, kullanıcıyı o zaman diliminde başka şeyler yapabilirken, bir işlemin tamamlanmasını bekletmemektir. Eşzamansız işlemlerinizden birinin tamamlanmasının 3 dakika sürdüğünü varsayalım, eşzamansız işlemler olmasaydı arayüz 3 dakika donacaktı.


Önerilen Okuma:

Bu cevabın asıl değeri şu şekildedir: Eşzamansız bir aramadan gelen yanıtı nasıl geri getirebilirim?

Ancak, angular2 sürümüyle birlikte daktilo ve gözlemlenebilirlerle tanıştık, bu nedenle bu yanıtın, gözlemlenebilirlerle eşzamansız bir isteği ele almanın temellerini kapsadığını umuyoruz.


3
Soru soran kişi tarafından bir soru yanıtlandığında, bunun yerine bir blog yazısı yazmak için iyi bir yer
Jonas Praem

3
@JonasPraem Doğru, ancak Stackoverflow'da bilgi paylaşımında yanlış bir şey yok. Oy sayılarını gördüğünüz gibi buradaki birçok kişiye yardımcı oldu ve yapmaya da devam edecek.
Amit Chigadani

11

Angular / javascript ile http çağrısı yapmak asenkron bir işlemdir. Dolayısıyla, http çağrısı yaptığınızda, bu çağrıyı bitirmek ve bir sonraki satırı başka bir evre ile yürütmek için yeni bir evre atayacaktır. Bu yüzden tanımsız bir değer elde ediyorsunuz. bu yüzden bunu çözmek için aşağıdaki değişikliği yapın

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


3

Gözlemlenebilirler tembeldir, bu nedenle değeri almak için abone olmanız gerekir. Kodunuza düzgün bir şekilde abone oldunuz, ancak eşzamanlı olarak çıkışı 'abone' bloğunun dışında kaydettiniz. Bu yüzden 'tanımsız'.

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

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

Bu nedenle, abonelik bloğunun içine kaydederseniz, yanıtı doğru şekilde günlüğe kaydedecektir.

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

3

Burada sorun, sen başlatılıyor edilir this.myEventsiçine subscribe()yapıyorsun ederken hangi bir zaman uyumsuz blok console.log()sadece dışarı subscribe()bloğu. Yani console.log()önceden çağrılmak this.myEventsbaşlatılır.

Lütfen console.log () kodunuzu subscribe () içine de taşıyın ve bitirdiniz.

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

2

Sonuç tanımsızdır çünkü açısal süreç eşzamansızdır. aşağıdaki gibi deneyebilirsiniz:

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

1

Ayrıca yanıtınızı bir json çıktısına eşlediğinizden emin olun. Aksi takdirde düz metin döndürecektir. Bunu şöyle yaparsın:

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

Tanımlanmamıştır çünkü buradaki değer, hizmetten herhangi bir veri yukarıdaki abone hizmet çağrısından ayarlanmadan önce kaydedilir. Bu nedenle, ajax çağrısı bitene kadar beklemeniz ve verileri yanıt verilerinden ayarlamanız gerekir.

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

Burada, myEvents değişkeninde veri ayarlandığında günlüğü oluşturacak olan abonelik yöntemi içinde Konsol günlüğünü yapın.

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

0

Bu yöntemi deneyebilirsiniz.

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');
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.