Làm cách nào để trả về giá trị từ hàm có đăng ký Observable bên trong?


96

Tôi không biết cách trích xuất giá trị từ Observable để được trả về bởi hàm trong đó Observable có mặt. Tôi chỉ cần một giá trị từ nó để được trả lại, không có gì khác.

Phiên bản hiện tại hoạt động

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

Tôi cần cái này hoạt động, hàm để trả về giá trị và sau đó:

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

Tôi làm gì sai ở đây?


2
Bạn nên trả lại một Lời hứa / Có thể quan sát và chuyển dữ liệu qua nó khi có thể quan sát được của bạn được giải quyết
galvan

2
Bạn có thể đặt một số mã đơn giản cho điều này?
Teddy

6
Những gì bạn đang cố gắng đạt được là một mô hình chống: Bạn đang cố gắng "đồng bộ hóa" một tác vụ không đồng bộ. Đó không phải là cách các vật quan sát được cho là hoạt động. Nói tóm lại, trong hầu hết các trường hợp, một hàm có đầu vào là có thể quan sát được cũng sẽ trả về có thể quan sát được - hoặc không trả về gì. Và khi bạn cần làm điều gì đó với đầu ra, hãy đăng ký với nó. Trường hợp này nếu bạn muốn console.log data thì cứ làm bên trongsubscribe
Can Nguyen

1
Tôi hiểu tất cả những gì bạn nói. Tôi chỉ đang sử dụng bảng điều khiển log làm bản demo, tôi sẽ sử dụng thêm dữ liệu đó, đó là lý do tại sao tôi cần nó để ghi bảng điều khiển bên ngoài có thể quan sát được. Vấn đề là phải có chức năng mà khi bạn có thể đăng ký dữ liệu có thể quan sát, lấy dữ liệu, hủy đăng ký và trả về dữ liệu trong chức năng đó để tôi có thể sử dụng dữ liệu đó hơn nữa. Tôi biết nó là chống lại khuôn mẫu, nhưng tôi cần nó hoạt động. Bất kỳ trợ giúp được đánh giá cao. Hiện tại giải pháp của tôi hoạt động, nhưng tôi không quá tin tưởng về nó.
Teddy

4
Xin hãy chú ý! Mã từ phần 'GIẢI PHÁP' hoàn toàn không chính xác. Đừng sử dụng nó! Nó sẽ chỉ hoạt động nếu phần this.store.subscribe ((data: any) => {output = data}) .unsubscribe () sẽ được hoàn thành cho đến khi trả về. Nếu không, nó sẽ trả về không xác định.
Rodion Golovushkin

Câu trả lời:


56

CHỈNH SỬA: mã được cập nhật để phản ánh những thay đổi được thực hiện đối với cách đường ống hoạt động trong các phiên bản RXJS mới hơn. Tất cả các toán tử (lấy trong ví dụ của tôi) bây giờ được bao bọc trong toán tử pipe ().

Tôi nhận thấy rằng Câu hỏi này đã khá lâu trước đây và chắc chắn bạn đã có một giải pháp thích hợp cho đến bây giờ, nhưng đối với bất kỳ ai đang tìm kiếm vấn đề này, tôi sẽ đề xuất giải quyết nó bằng Lời hứa giữ nguyên mẫu không đồng bộ.

Một phiên bản dài hơn sẽ tạo ra một Lời hứa mới:

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

Ở đầu nhận, sau đó bạn sẽ phải "đợi" lời hứa sẽ giải quyết bằng một cái gì đó như sau:

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

Một giải pháp mỏng hơn sẽ là sử dụng RxJS '.toPromise () thay thế:

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

Tất nhiên bên nhận vẫn giữ nguyên như trên.


Kiểu trả về của getValueFromObservablehàm của bạn là gì?
hardywang 27/09/18

Nên là một lời hứa với bất kỳ loại dữ liệu cửa hàng nào. ví dụ như Promise <StoreType>
jparg

4
bạn vẫn đang trả lại một lời hứa cần được giải quyết và không trực tiếp trả lại giá trị.
Roj

1
Thuộc tính 'take' không tồn tại trên loại 'Có thể quan sát được <>'
Memmo

1
@Memmo hãy thử .pipe (lấy (1)) thay thế
Thibault

20

Đây không phải là ý tưởng chính xác về việc sử dụng Observable

Trong thành phần, bạn phải khai báo thành viên lớp sẽ chứa một đối tượng (thứ mà bạn sẽ sử dụng trong thành phần của mình)

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

Sau đó, a Servicesẽ trả lại cho bạn một Observable:

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

Component nên tự chuẩn bị để có thể lấy một giá trị từ nó:

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

Bạn phải gán một giá trị từ một Observablecho một biến:

Và mẫu của bạn sẽ sử dụng nhiều biến name:

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

Một cách khác để sử dụng Observablelà thông qua asyncđường dẫn http://briantroncone.com/?p=623

Lưu ý : Nếu đó không phải là những gì bạn đang hỏi, vui lòng cập nhật câu hỏi của bạn với nhiều chi tiết hơn


Cũng không khá. Vấn đề là dữ liệu được ghi lại bên trong có thể quan sát và tôi chỉ có thể ghi lại bảng điều khiển. Tôi muốn trả lại giá trị đó và console.log hoặc bất kỳ thứ gì từ tệp khác bằng cách gọi hàm mà nó nằm trong đó.
Teddy

Andrei đã chỉ ra cách tạo namekhả dụng bên ngoài lệnh gọi lại bằng cách gán nó cho namebiến của thành phần . Không thể trả lại nameđồng bộ trong trường hợp của bạn.
Matt

@ Matt: Tôi không thể sử dụng nó trong Oninitnhư thế, làm gì nếu tôi cần phải trả lại một cách rõ ràng, gọi vẻ Mã của tôi như thế này this.actions$.ofType(SearchActions.SEARCH_MULTIPLE_NEW_QUERY).map(toPayload).fnWithMultipleAsyncReturns()
ishandutta2007

@ ishandutta2007 Chào bạn. Tốt hơn bạn nên tạo một câu hỏi mới trên SO về vấn đề của bạn.
Matt

@Matt: đã tạo, trong trường hợp bạn muốn xem ( stackoverflow.com/questions/43381922/… )
ishandutta2007

7

Nếu bạn muốn đăng ký trước cùng một Observable sẽ được trả lại, chỉ cần sử dụng

.do ():

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

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

3
Bạn cũng có thể sử dụng các toán khác như .map(data => data)mà làm điều tương tự và sau đó đăng ký nó bất cứ nơi nào bạn mong đợi kết quả
ashok_khuman

Tôi đồng ý với ashok_khuman. Đây là hướng dẫn angle.io/guide/pipes
Armando Perea

Đây có thể là một câu trả lời hay, nhưng thực tế là bạn không giải thích gì về nó, khiến nó trở thành một câu trả lời tồi. "Đăng ký trước" nghĩa là gì? Và nó có nên giải quyết câu hỏi từ bộ mở luồng không?
Florian Leitgeb

lưu ý rằng trong RxJS 6 dobây giờ được gọi tapvà bạn phải sử dụng nó trong một đường ống. Cũng lưu ý rằng tapcó nhiều tham số cho bộ xử lý khác nhau như next, completeerror.
Simon_Weaver

6

Vấn đề là dữ liệu được thu thập bên trong có thể quan sát và tôi chỉ có thể ghi lại bảng điều khiển. Tôi muốn trả về giá trị đó và console.log hoặc bất kỳ thứ gì từ tệp khác bằng cách gọi hàm mà nó nằm trong đó.

Có vẻ như bạn đang tìm kiếm một bộ thu "giá trị hiện tại" bên trong một thiết bị có thể quan sát được, khi nó phát ra và sau khi phát ra.

SubjectObservablekhông có một thứ như vậy. Khi một giá trị được phát ra, nó sẽ được chuyển cho người đăng ký của nó và việc Observablenày được thực hiện với nó.

Bạn có thể sử dụng BehaviorSubjectgiá trị nào lưu trữ giá trị phát ra cuối cùng và phát ngay lập tức cho người đăng ký mới.

Nó cũng có một getValue()phương thức để lấy giá trị hiện tại;

Đọc thêm:

RxJS BehaviorSubject

Làm thế nào để nhận được giá trị hiện tại của RxJS Subject hoặc Observable?


2

Các giá trị quan sát được có thể được truy xuất từ ​​bất kỳ vị trí nào. Chuỗi nguồn đầu tiên được đẩy lên một thiết bị quan sát đặc biệt có thể phát ra ở nơi khác. Điều này đạt được với lớp Chủ đề từ Phần mở rộng phản ứng (RxJS).

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

Lưu trữ giá trị vào người quan sát .

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

Để lấy giá trị từ nơi khác, hãy đăng ký người quan sát như sau:

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

Đối tượng vừa là Người quan sát vừa là Người quan sát. Có các loại Chủ đề khác như BehaviourSubject và ReplaySubject cho các tình huống sử dụng khác.

Đừng quên nhập RxJS.

var Rx = require('rxjs');

1

Mặc dù các câu trả lời trước đó có thể hoạt động theo thời gian, nhưng tôi nghĩ rằng sử dụng BehaviorSubject là cách chính xác nếu bạn muốn tiếp tục sử dụng có thể quan sát.

Thí dụ:

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

Trong dịch vụ:

let myBehaviorSubject = new BehaviorSubjet(value);

Trong component.ts:

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

Tôi hi vọng cái này giúp được!


0

Ví dụ đây là mẫu html của tôi:

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

Đây là trường liên kết với mẫu từ Thành phần của tôi:

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

Tôi tìm nạp động các thể loại phim từ máy chủ. Để giao tiếp với máy chủ, tôi đã tạoFilmService

Đây là phương pháp giao tiếp máy chủ:

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

Tại sao phương thức này trả về Observable<Genre[]>không giống như Genre[]vậy?

JavaScript là asyncvà nó không chờ đợi một phương pháp để giá trị trả về sau một quá trình tốn kém. Với đắt tiền, tôi có nghĩa là một quá trình mất một thời gian để trả lại giá trị. Như tìm nạp dữ liệu từ máy chủ. Vì vậy, bạn phải trả về tham chiếu của Observable và đăng ký nó.

Ví dụ trong Thành phần của tôi:

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

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

Trong trường hợp trên console.log chạy trước khi lời hứa được giải quyết nên không có giá trị nào được hiển thị, hãy thay đổi nó thành sau

function getValueFromObservable() {
    return this.store
}

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

giải pháp khác là khi bạn cần dữ liệu bên trong getValueFromObservable để trả về toán tử có thể quan sát được và đăng ký vào hàm.

 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

Trong thế giới javascript đơn luồng, không đồng bộ, hướng hứa hẹn, xu hướng phản ứng async/awaitlà người bạn tốt nhất của lập trình viên kiểu mệnh lệnh:

(async()=>{

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

})();

Và trong trường hợp storelà một chuỗi nhiều giá trị:

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

0

Cách hợp lý là trả về có thể quan sát được từ một hàm và đăng ký nó ở bất cứ đâu được yêu cầu, bởi vì các đối tượng quan sát là lười biếng, chúng sẽ bắt đầu phát ra các giá trị chỉ khi chúng được đăng ký.

Ở đây, tôi có một giải pháp điều khiển sự kiện thú vị hơn, mà ban đầu tôi đã sử dụng. Ví dụ sau thực hiện điều này bằng cách sử dụng mô-đun " sự kiện " của nodejs. Bạn có thể sử dụng nó với các khung công tác khác có mô-đun tương tự ( Lưu ý : Cú pháp và kiểu có thể thay đổi tùy thuộc vào mô-đun được sử dụng).

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

Nó chỉ là một ví dụ để giới thiệu một ý tưởng mà chúng ta có thể truyền dữ liệu từ những nơi khác nhau bằng phương pháp phát và nghe. Đây còn được gọi là mã hướng sự kiện.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.