DarkNik
DarkNik

Reputation: 823

Angular service method execution order

I'm new in Angular and now trying to learn it and have a problem. I have a simple service method which I call in another component. But I have strange order of execution:

enter image description here

You can see it in console browser:

enter image description here

Could anyone please explain how does it work? And how to fix it?

Upvotes: 1

Views: 5258

Answers (3)

NULLchimp
NULLchimp

Reputation: 775

This has to do with the fact, that I/O operations are usually designed to be non-blocking. Setting up a request via http.get is such a non-blocking operation. It takes time to complete and in the meanwhile your other code will run first.

You wouldn't want your app to freeze while it waits for a 5sec response from the server would you?

If you would like to display your result you may just split up your logic for that, like so:

_weatherForecast: WeatherForecast = null;

calculateWeatherForecast() {
  this.http.get<WeatherForecast>(this._url).subscribe((data) => {
      this._weatherForecast = data;
  });
}

getWeatherForecast() {
    return this._weatherForecast;
}

That way you may fetch your data independently from displaying them. Angular would detect the change of your variable and render the result. In your template you would just do:

<div>{{getWeatherForecast()}}</div>

That has the advantage that you won't fetch new data from the server, every time you want to display your weatherForecast. It gives you more control over how often and when to ask your server for new data.

Edit:

As it was pointed out in the comments, the code will break, when trying to access a property (in that case summary) on _weatherForecast. If you would like to avoid that you have two options:

  1. Change your template to:
<div>{{ getWeatherForecast()?.summary }}</div>
  1. Change the logic in your component to:
getWeatherForecast() {
    if(this._weatherForecast) {
        return this._weatherForecast.summary;
    }
}

You may also change the method getWeatherForecast() to get weatherForecast(). That way you may access it in your template like a property of your component, like so:

<div>{{ weatherForecast?.summary }}</div>

Upvotes: 1

maryrio7
maryrio7

Reputation: 330

The code outside the subscribe() method is always executed last. It doesn't matter if it's before or after if it's at the same level.

To fix it instead of doing a "get" method, use a global variable and initialize it on ngOnInit().

weather :WeatherForecast = null;

ngOnInit(){
  this.http.get<WeatherForecast>(this._url).subscribe(
    data => {
       this.weather = data;
    }
  )
}

I suggest you to organize http calls between component.ts and a service to make it more independent.

Upvotes: 1

asimhashmi
asimhashmi

Reputation: 4378

There are 2 portions in your code:

Synchronous

The part outside of your subscribe method is synchronous i.e. it will execute instantly following your program flow of execution.

Asynchronous

The part inside your subscribe method is asynchronous i.e. it will only execute when the get request is completed ( response is returned ).

Explanation

Now since the http request to the server will take some time. so the synchrouns part will continue its execution and it will not wait for get request to complete. so the console.log [1] will execute first.

The line

return this.weatherForcast

is executed next due to synchronous code and return undefined which causes error inside console [2]

Your subscribe function is then called at some point later in time (when get request is completed) and data is shown in console [3].

Upvotes: 1

Related Questions