Correct way to handle asynchronous call & return in Typescript

Hi
I’m working on an Ionic 4 project. This is quite new for me to work in Javascript / Typescript and i’m having a hard time to understand how to use properly async / await / promise and all that stuff.

What i have :

On a page of my app (Let’s call it tab1.page.ts ) I have a function that call a function of my service :

Get_Sim_Agents() {
       this.simConfig.Get_Sim_Agents();
    }

On my service page, here is the function : (a basic http get function) :

/**
     * Fetch the datas in order to populate the app
     * */
    Get_Sim_Agents(){

        this.http.get(
            "http://" +
            this.ip_address +
            ":" +
            this.port +
            "/get_datas"
        ).subscribe(response => {

            var data = JSON.stringify(response, null, 2);

            try {
                var obj = JSON.parse(data);
                // here i do stuff with the retrieved data
                });

            } catch (e) {
                console.log(e);
            }
        });
    }

And everything is working. But i would like my service function to return the data as a string when the data is retrieved & treated. I’m having a hard time finding the correct syntax.
Here is what i tryed :

On my service :

/**
     * Fetch the Sim_Agents from the Simulation_orchestrator in order to populate the app
     * */
    async Get_Sim_Agents() : Promise<string>{

        this.http.get(
            "http://" +
            this.simulation_orchestrator_ip_address +
            ":" +
            this.simulation_orchestrator_port +
            "/get_sim_agents"
        ).subscribe(response => {

            var data = JSON.stringify(response, null, 2);

            // here i do some stuff about the data

            return JSON.parse(data);
            });

        return 'test';
    }

On my page :

Get_Sim_Agents() {
        this.simConfig.Get_Sim_Agents().then((result) => {console.log(result)});
    }

With this code my function called on my page return ‘test’ right away. I would like it to wait until the http get return the server response. I tryed several different syntax but couldn’t achieved what i want :confused:

I someone could help me to overcome this trouble i would be gratefull <3

tab1.page.ts

Get_Sim_Agents() {
       this.simConfig.Get_Sim_Agents()
                  .subscribe( ... all that stuff)
    }

ps. stringifying and then parsing the response seems a waste. Not sure why you are doing that.

the service:

 Get_Sim_Agents() : Observable<string>{

        return this.http.get(
            "http://" +
            this.simulation_orchestrator_ip_address +
            ":" +
            this.simulation_orchestrator_port +
            "/get_sim_agents"
        );
}

You either go for promises (async await) or observables (subscribe). You can mix them as you are trying in your code but that is a waste of your time, the app and the intellect of the people that invented both concepts. My opinion. :slight_smile:

And mostly if you have a service, every method of the service returns something. So the first word to type is return. Any method in the service that doesn’t, needs critical scrutiny or made private.

Pretty sure there is more to comment about the code, but this seems to be the core/first step of the answer to your question.

1 Like

Thanks for your reply.
With your solution the service is just calling the request, and sending the result to the page.

But what if i want to do some stuff about the data in my service before sending back the result to the page ?

Like:

  1. The page call the service function
  2. the service make the request, and got a reply
  3. the service do stuff (populating the app with the datas per example)
  4. then it send a string back to the page , like “job is done”

Thanks again

Hi
I suggest going through the Tour of Heroes on angular.io. Will help a lot on everything related to ionic, angular, typescript, rxjs etc.

https://angular.io/tutorial

Other info: https://angular.io/guide/http
https://angular.io/guide/observables

You should use RXJS operators to work on the datastream (using pipe). And return the resulting observable to the page that subscribes to it.

Example: https://www.concretepage.com/angular/angular-rxjs-filter

1 Like

I found the solution :slight_smile:

/**
     * Fetch the Sim_Agents from the Simulation_orchestrator in order to populate the app
     * */
    async Get_Sim_Agents() : Promise<string>{

        return this.http.get(
            "http://" +
            this.simulation_orchestrator_ip_address +
            ":" +
            this.simulation_orchestrator_port +
            "/get_sim_agents"
        ).toPromise().then(response => {

            var data = JSON.stringify(response, null, 2);

            // here i do some stuff about the data

            return JSON.parse(data);
        });
    }

Surely gets this month’s reward for funniest anti pattern. First time I have seen this meshup of observables and promises

But hey, if it works for you, why care!

:grinning:

The only reason this even compiles is part of why I keep harping on people that pollute their own code with any.

JSON.parse is returning an object. It doesn’t know the type of said object, so it’s declared as any. It is definitely not a string, so callers of this function are going to be surprised with what they get.

You shouldn’t even be calling JSON.anything, though.

Angular’s HttpClient knows that 95% of the time, it’s being used as you are here, to sling objects around. It takes a template parameter, so the way I would write this is more like so:

interface SimAgentWired {
  id: string;
  // whatever other stuff comes over the wire from the raw HTTP response
}

// this is the form we work with in the app
export interface SimAgent {
  id: string;
  rank: number;
  name: string;
  // &c
}

private unwireSimAgent(wsa: SimAgentWired): SimAgent {
  // here you do some stuff about a single agent
}

allSimAgents(): Observable<SimAgent[]> {
  return this.http.get<SimAgentWired[]>.pipe(
    map(wsas => wsas.map(wsa => this.unwireSimAgent(wsa)));
}

Now you get all the benefits of strict type checking throughout, you can massage each SimAgent as necessary.