0
votes

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.

4

4 Answers

0
votes

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

Ideally you should return the Observable from the call to getDataStream() in the getRealTimePrice method and do the subscription at the place where the data is expected.

0
votes

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.

0
votes

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