İçinde Gözlemlenebilir abonelik bulunan işlevden değer nasıl döndürülür?


98

Gözlemlenebilir'in mevcut olduğu işlev tarafından döndürülecek olan Gözlemlenebilir'den nasıl değer çıkaracağımı bilmiyorum. İade edilmesi için ondan sadece bir değere ihtiyacım var, başka bir şey yok

Çalışan mevcut sürüm

function getValueFromObservable() {
    this.store.subscribe(
        (data:any) => {
            console.log(data)
        }
    )
}
getValueFromObservable()

Bunun çalışması için buna ihtiyacım var, değer döndürmek için işlev ve sonra:

function getValueFromObservable() {
    this.store.subscribe(
        (data:any) => {
            return data
        }
    )
}
console.log(getValueFromObservable())

Burada neyi yanlış yapıyorum?


2
Gözlemlenebilir
durumunuz

2
Bunun için basit bir kod koyabilir misiniz?
Teddy

6
Başarmaya çalıştığınız şey bir anti-modeldir: Bir asenkron görevi "senkronize etmeye" çalışıyorsunuz. Gözlenebilirlerin çalışması gereken yol bu değil. Kısacası, çoğu durumda, girdi olarak gözlemlenebilir olan bir işlev, aynı zamanda bir gözlemlenebilir - veya hiçbir şey döndürmemelidir. Ve çıktıyla bir şey yapmanız gerektiğinde, ona abone olun. Bu durumda verileri console.log yapmak istiyorsanız, sadece içeride yapınsubscribe
Can Nguyen

1
Tüm söylediğini anlıyorum. Konsol günlüğünü demo olarak kullanıyorum, bu verileri daha fazla kullanacağım, bu yüzden gözlemlenebilirin dışında konsolda oturum açmak için ona ihtiyacım var. Önemli olan, gözlemlenebilir olana abone olabileceğiniz, verileri alabileceğiniz, aboneliğinizi iptal ettiğiniz ve bu fonksiyondaki verileri geri döndüren bir işleve sahip olmaktır, böylece bu verileri daha fazla kullanabilirim. Kalıp karşıtı olduğunu biliyorum, ama işe yaraması gerekiyor. Herhangi bir yardım takdir edilmektedir. Mevcut çözümüm işe yarıyor, ancak bu konuda çok emin değilim.
Teddy

4
Lütfen dikkat! 'ÇÖZÜM' bölümündeki kod kesinlikle yanlış. Onu kullanma! Yalnızca this.store.subscribe ((data: any) => {output = data}) .unsubscribe () bölümü geri dönene kadar biterse çalışacaktır. Aksi takdirde tanımsız olarak dönecektir.
Rodion Golovushkin

Yanıtlar:


58

DÜZENLEME: RXJS'nin daha yeni sürümlerinde boruların çalışma biçiminde yapılan değişiklikleri yansıtmak için güncellenmiş kod. Tüm operatörler (benim örneğimi ele alalım) artık pipe () operatörüne sarılmıştır.

Bu sorunun epey bir zaman önce olduğunu ve şimdiye kadar kesinlikle uygun bir çözüme sahip olduğunuzun farkındayım, ancak bunu arayan herhangi biri için asenkron kalıbı korumak için bir Sözle çözmeyi öneririm.

Daha ayrıntılı bir versiyon, yeni bir Promise yaratmak olacaktır:

function getValueFromObservable() {
    return new Promise(resolve=>{
        this.store.pipe(
           take(1) //useful if you need the data once and don't want to manually cancel the subscription again
         )
         .subscribe(
            (data:any) => {
                console.log(data);
                resolve(data);
         })
    })
}

Alıcı tarafta, sözün şu şekilde çözülmesi için "bekle" ye sahip olacaksınız:

getValueFromObservable()
   .then((data:any)=>{
   //... continue with anything depending on "data" after the Promise has resolved
})

Daha ince bir çözüm bunun yerine RxJS '.toPromise () kullanmak olacaktır:

function getValueFromObservable() {
    return this.store.pipe(take(1))
       .toPromise()   
}

Alıcı taraf elbette yukarıdakiyle aynı kalır.


getValueFromObservableİşlevinizin dönüş türü nedir ?
hardywang

Depo verisi ne tür olursa olsun bir söz olmalıdır. ör. Promise <StoreType>
jparg

4
Hala çözülmesi gereken bir sözü geri veriyorsunuz ve doğrudan bir değer vermiyorsunuz.
Roj

1
'Gözlemlenebilir <>' türünde 'alma' özelliği mevcut değil
Memmo

1
@Memmo bunun yerine .pipe'ı deneyin ((1) alın)
Thibault

20

Bu tam olarak doğru kullanma fikri değil Observable

Bileşende, bir nesneyi tutacak bir sınıf üyesi bildirmeniz gerekir (bileşeninizde kullanacağınız bir şey)

export class MyComponent {
  name: string = "";
}

O zaman Servicesize bir geri dönecek Observable:

getValueFromObservable():Observable<string> {
    return this.store.map(res => res.json());
}

Component ondan bir değer alabilmek için kendini hazırlamalıdır:

OnInit(){
  this.yourServiceName.getValueFromObservable()
    .subscribe(res => this.name = res.name)
}

ObservableBir değişkene bir değer atamanız gerekir :

Ve şablonunuz değişken tüketecek name:

<div> {{ name }} </div>

Kullanmanın diğer bir yolu Observablearacılığıyla asyncboru http://briantroncone.com/?p=623

Not : Sorduğunuz bu değilse, lütfen sorunuzu daha fazla ayrıntıyla güncelleyin


Pek iyi değil. Sorun şu ki, veriler gözlemlenebilir olanın içinde yakalanır ve ben sadece konsolide edebilirim. İçinde bulunduğu işlevi çağırarak bu değeri ve console.log'u veya farklı bir dosyadan herhangi bir şeyi döndürmek istiyorum.
Teddy

Andrei name, onu bileşenin namedeğişkenine atayarak geri aramanın dışında nasıl kullanılabilir hale getirileceğine dikkat çekti . nameSizin durumunuzda eşzamanlı olarak geri dönmek mümkün değildir .
Matt

@Matt: Bunu böyle kullanamam Oninit, Ya açıkça geri dönmem gerekirse, arama kodum şöyle görünüyor this.actions$.ofType(SearchActions.SEARCH_MULTIPLE_NEW_QUERY).map(toPayload).fnWithMultipleAsyncReturns()
ishandutta2007

@ ishandutta2007 Merhabalar. Sorununuzla ilgili olarak SO'da yeni bir soru oluştursanız iyi olur.
Matt

@Matt: bir göz atmak istemeniz durumunda oluşturuldu ( stackoverflow.com/questions/43381922/… )
ishandutta2007

7

İade edilecek olan aynı Gözlemlenebilir'e önceden abone olmak istiyorsanız, şunu kullanın:

.yapmak():

function getValueFromObservable() {
    return this.store.do(
        (data:any) => {
            console.log("Line 1: " +data);
        }
    );
}

getValueFromObservable().subscribe(
        (data:any) => {
            console.log("Line 2: " +data)
        }
    );

3
.map(data => data)Aynı şeyi yapan diğer operatörleri de kullanabilir ve sonucu beklediğiniz her yerde abone olabilirsiniz
ashok_khuman

Ashok_khuman'a katılıyorum. İşte kılavuz angular.io/guide/pipes
Armando Perea

Bu iyi bir cevap olabilir, ama aslında onun hakkında hiçbir şey açıklamamış olmanız, onu kötü bir cevap haline getiriyor. "Ön abone" ne anlama geliyor? Ve soruyu iplik açıcıdan çözmeli mi?
Florian Leitgeb

RxJS 6'da doartık çağrıldığını tapve bunu bir boru içinde kullanmanız gerektiğini unutmayın . Ayrıca , ve tapgibi farklı işleyiciler için birden çok parametre aldığına dikkat edin . nextcompleteerror
Simon_Weaver

7

Sorun şu ki, veriler gözlemlenebilir olanın içinde yakalanır ve ben sadece konsolide edebilirim. İçinde bulunduğu işlevi çağırarak bu değeri ve console.log'u veya farklı bir dosyadan herhangi bir şeyi döndürmek istiyorum.

Görünüşe göre, bir emisyon yayarken ve sonrasında gözlemlenebilir bir cihazın içinde "mevcut değer" alıcıyı arıyorsunuz.

Subjectve Observableböyle bir şeye sahip değil. Bir değer çıktığında abonelerine aktarılır ve onunla Observableyapılır.

En BehaviorSubjectson çıkarılan değeri depolayan ve yeni abonelere hemen gönderenleri kullanabilirsiniz.

Aynı zamanda getValue()mevcut değeri elde etmek için bir yöntemi vardır ;

Daha fazla okuma:

RxJS BehaviorSubject

RxJS Öznesi veya Gözlemlenebilir'in mevcut değeri nasıl elde edilir?


2

Gözlemlenebilir değerler herhangi bir yerden alınabilir. Kaynak dizisi, birinci bir itilir özel üzerine gözlemci başka yayan edebilmektedir. Bu, Reaktif Uzantılardan (RxJS) Konu sınıfıyla elde edilir .

var subject = new Rx.AsyncSubject();  // store-last-value method

Gözlemciye değer depolayın .

subject.next(value); // store value
subject.complete(); // publish only when sequence is completed

Değeri başka bir yerden almak için, gözlemciye şu şekilde abone olun:

subject.subscribe({
  next: (response) => {
      //do stuff. The property name "response" references the value
  }
});

Konular hem Gözlemlenebilirler hem de Gözlemcilerdir. Diğer kullanım senaryoları için BehaviourSubject ve ReplaySubject gibi başka Konu türleri vardır .

RxJS'yi içe aktarmayı unutmayın.

var Rx = require('rxjs');

1

Önceki cevaplar bir şekilde işe yarasa da, gözlemlenebilirleri kullanmaya devam etmek istiyorsanız BehaviorSubject kullanmanın doğru yol olduğunu düşünüyorum.

Misal:

    this.store.subscribe(
        (data:any) => {
            myService.myBehaviorSubject.next(data)
        }
    )

Serviste:

let myBehaviorSubject = new BehaviorSubjet(value);

Component.ts içinde:

this.myService.myBehaviorSubject.subscribe(data => this.myData = data)

Umarım bu yardımcı olur!


0

Örneğin bu benim html şablonum:

<select class="custom-select d-block w-100" id="genre" name="genre"
                  [(ngModel)]="film.genre"
                  #genreInput="ngModel"
                  required>
            <option value="">Choose...</option>
            <option *ngFor="let genre of genres;" [value]="genre.value">{{genre.name}}</option>
          </select>

Bu, Bileşenimdeki şablonla bağlanan alandır:

  // Genres of films like action or drama that will populate dropdown list.
  genres: Genre[];

Sunucudan dinamik olarak film türlerini alıyorum. Oluşturduğum sunucu ile iletişim kurmak içinFilmService

Bu, sunucuyla iletişim kuran yöntemdir:

 fetchGenres(): Observable<Genre[]> {
    return this.client.get(WebUtils.RESOURCE_HOST_API + 'film' + '/genre') as Observable<Genre[]>;
  }

Bu yöntem neden Observable<Genre[]>böyle bir şey döndürmüyor Genre[]?

JavaScript, asyncpahalı bir işlemden sonra bir yöntemin değer döndürmesini beklemez. Pahalıyla, değer döndürmesi zaman alan bir süreci kastediyorum. Sunucudan veri almak gibi. Yani zorunda gözlemlenebilir bir başvuru döndürmek ve onu abone olun.

Örneğin Bileşenimde:

ngOnInit() {
    this.filmService.fetchGenres().subscribe(
      val => this.genres = val
    );
  }

0
function getValueFromObservable() {
    this.store.subscribe(
        (data:any) => {
            return data
        }
    )
}
console.log(getValueFromObservable())

Yukarıdaki durumda, console.log söz çözülmeden önce çalışır, bu nedenle hiçbir değer görüntülenmez, aşağıdaki gibi değiştirin

function getValueFromObservable() {
    return this.store
}

getValueFromObservable()
 .subscribe((data: any) => {
    // do something here with data
    console.log(data);
});

diğer bir çözüm, operatörün gözlemlenebilir kullanımını döndürmek ve işleve abone olmak için getValueFromObservable içindeki verilere ihtiyaç duyduğunuz zamandır.

 function getValueFromObservable() {
        return this.store.subscribe((data: any) => {
            // do something with data here
            console.log(data);
            //return again observable.
            return of(data);
       })
    }

    getValueFromObservable()
     .subscribe((data: any) => {
        // do something here with data
        console.log(data);
    });

0

Javascript'in tek iş parçacıklı, eşzamansız, vaat odaklı, reaktif trendli dünyasında async/await, zorunlu stil programcının en iyi arkadaşı:

(async()=>{

    const store = of("someValue");
    function getValueFromObservable () {
        return store.toPromise();
    }
    console.log(await getValueFromObservable())

})();

Ve storebirden çok değer dizisi olması durumunda :

  const aiFrom = require('ix/asynciterable').from;
  (async function() {

     const store = from(["someValue","someOtherValue"]);
     function getValuesFromObservable () {
        return aiFrom(store);
     }
     for await (let num of getValuesFromObservable()) {
       console.log(num);
     }
  })();

Veri dizisi olması durumunda neden eşzamansızlık kullanmalıyım?
Janos Vinceller

@JanosVinceller Bu, kodun diğer kısımlarına odaklanmak için sadece bir örnektir. from(["someValue","someOtherValue"])Birden fazla değer yayan, seçtiğiniz bir gözlemlenebilir ile değiştirebilirsiniz . Sanırım kullanılmış olması daha uygun olabilir interval(1000).
Marinos An

0

İyi bir yol, gözlemlenebilir olanı bir fonksiyondan geri döndürmek ve gerektiğinde ona abone olmaktır, çünkü gözlemlenebilirler tembeldir, sadece abone olduklarında değerleri yaymaya başlarlar.

Burada, başlangıçta üzerinde oynadığım, olay odaklı bir çözüm daha var. Aşağıdaki örnek, nodejs'nin " olaylar " modülünü kullanarak bunu yapar . Bunu benzer modüllerin bulunduğu diğer çerçevelerle kullanabilirsiniz ( Not : Sözdizimi ve stil, kullanılan modüle bağlı olarak değişebilir).

var from =require("rxjs").from;
var map = require("rxjs/operators").map;
var EventEmitter = require("events");

function process(event) {
    from([1,2,3]).pipe(
        map(val => `The number is:: ${val}`)
    ).subscribe((data) => {
       event.emit("Event1", data); //emit value received in subscribe to the "Event1" listener
    });
}

function main() {
   class Emitter extends EventEmitter{};
    var event = new Emitter(); //creating an event
    event.on("Event1", (data)=>{ //listening to the event of name "Event1" and callback to log returned result
        console.log(data); //here log, print, play with the data you receive
    });
    process(event); //pass the event to the function which returns observable.
}

main(); //invoke main function

Verileri yayma ve dinleme yöntemiyle farklı yerlerden aktarabileceğimiz bir fikri sergilemek için sadece bir örnek. Bu aynı zamanda olay odaklı kod olarak da bilinir.

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.