简体   繁体   中英

get a value from a Observable<value> object

I am writing a service function where is it supposed to reply the latest price of a product. I connect to my server - using websocket and I get a DataStream using the Rxjs observable, now the function in the service layer is supposed to reply back only the value and not the Observable object.

Sample code I am trying

public getRealTimePrice(id: string): number {

 let ws = new $WebSocket('/price?Id=' + id + '&connectionId=' + this.randomUUID());
    this.priceWebsocket = ws;

    this.priceWebsocket.getDataStream()
      .map(msg => JSON.parse(msg.data).price)
      .subscribe(responseNumber => {
        return responseNumber // by the time execution reaches here the context is changed.
      });
    // I am not returning anything on the function level - which results in a compilation error as per typescript.
  }

but for obviously reason I am unable to return the number - since it is inside the subscribe callback where the context changes and the function is async

How can I await for the reply from Observable and then return only the value received in the observable.

The only real way to do this is to return a promise. Because the call is asynchronous you wont be able to return just the value. Something like this would work:

public getRealTimePrice(id: string): Promise<number> {
    return new Promise((resolve, reject) => {
        let ws = new $WebSocket('/price?Id=' + id + '&connectionId=' + this.randomUUID());
        this.priceWebsocket = ws;

        this.priceWebsocket.getDataStream()
        .map(msg => JSON.parse(msg.data).price)
        .subscribe(responseNumber => {
            resolve(responseNumber);
        });
    });
}

Then you can call it like this:

getRealTimePrice().then((data:number) = {
    console.log(data);
});

理想情况下,您应该从getRealTimePrice方法中对getDataStream()的调用返回Observable,并在需要数据的位置进行预订。

I would suggest using toPromise like this:

public getRealTimePrice(id: string): Promise<number> {
    let ws = new $WebSocket('/price?Id=' + id + '&connectionId=' + this.randomUUID());
    this.priceWebsocket = ws;

    return this.priceWebsocket.getDataStream()
        .map(msg => JSON.parse(msg.data).price)
        .take(1)
        .toPromise()
}

Note take(1) operator which will take first value and also unsubscribe the DataStream.

Im not sure of the await feature of Angular but looking at the documentation it looks like it would be something like this:

public getRealTimePrice(id: string): Promise<number> {

    let ws = new $WebSocket('/price?Id=' + id + '&connectionId=' + this.randomUUID());
    this.priceWebsocket = ws;

    this.priceWebsocket.getDataStream()
      .map(msg => JSON.parse(msg.data).price)
      .subscribe(responseNumber => {
        return responseNumber
      })
      .take(1)
      .toPromise();
}

Then you can call it by using the await keyword:

async getAsyncValue(id: string) {
    const value = <number>await this.getRealTimePrice(id);
    console.log(`number: ${value}`);
}

Note that the function is prefixed with the "async" keyword, this is needed if the function has an "await" keyword within it.

The "async" keyword will mean that the console.log will not be hit until the promise from the "getRealTimePrice()" function is resolved (or rejected).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM