0

Angular returns observable when I call http get method. So I created local server to return 50 MB JSON file which contains all employee data like below.

import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import 'rxjs/add/operator/map'; @Injectable() export class DataServiceService { constructor(private _http: Http) {} getEmployeeData() { return this._http .get("http://localhost:3000/employees") .map(response => response.json()); } } 

App.Component.html

{{employeeData$ | async}} 

They say observable is a stream of data that could change over time.I was under the impression that the whole point of using observable is to start showing the data as soon as stream of employees start returning the data. However in the above example what I witness is that my page is blank for 30 seconds & then suddenly all the employee data starts showing up.

Then what is the point of using observable ? Can't I just load the whole data in a local array & then use that to show it on my HTML ?

Is there any way to achieve the behaviour such as, as soon as it starts recieving the first employee , start rendering it on html... so that user could start seeing the data instead of waiting for 30 seconds.

I understand that in real app I should be fetching only # of employees that user can see in the browser's view & then load the next set of employees.

8
  • Check the time taken to get response from server Commented Dec 20, 2017 at 4:32
  • @DeepakKumarTP this is what I see on server. It seems to be 27 seconds. GET /employees 200 27264.078 ms - - Commented Dec 20, 2017 at 4:36
  • Then the server is taking 30 seconds to get the response so nothing to do with angular observable. Check why server is taking 30 seconds to get response back Commented Dec 20, 2017 at 4:38
  • @DeepakKumarTP Okay I will check the server but could you also take time to answer about how can I achieve the behaviour that I asked in the question ? What is the point of returning Observable instead of the data itself ? Because of observable I have one extra step to use async pipe or to subscribe it to unroll the data from it. Commented Dec 20, 2017 at 4:40
  • Which back end technology are you using? Commented Dec 20, 2017 at 4:41

1 Answer 1

1

Angular's HTTP Observable only yield when the stream is complete, this is, when all the data has been transfered - So it only yields one time, one single value.

I'd say the BE doesn't have too many issues, those 30 seconds seems like it's just because it's a huge JSON: The amount of work to serialize/deserialize it can take a big chunk of time, and then you also have to download 50 Megs through the wire.

Something you could do is try to make your own "progressive" http call that returns a stream of employees every time you get a new chunk (with a low-level XMLHttpRequest, or try to find a library that does this).

But then trying to parse an incomplete JSON to get "the data I have received so far" is a terrible idea. For that I would even consider a multiple HTTP requests with pagination on each, so you get N-by-N employees you need.

Some example code following this approach:

function getEmployeeStream():Rx.Observable<Employee[]> { return Rx.Observable.interval(100) .concatMap( i => getEmployees(i) ) .takeUntil( employees => employees.length === 0 ) .scan( (allEmployees, receivedEmployees) => allEmployees.concat(receivedEmployees), [] ); } function getEmployees(page:number):Rx.Observable<Employee[]> { return this.http(...) .map(data => parseEmployees(data)); } 

So what this does is generate a new event every 100ms, then converting each event to a paginated call to the server, then tell it to keep going on while we get employees and finally concatenating them into a single array so it can be used by async pipe.

If you want to make many concurrent calls to get the data faster, you'll need to swap concatMap for a mergeMap with the concurrent parameter set, and then work around the case that the last call with employees.length === 0 will prevent the running calls to get through the stream (thus discarding those uncompleted calls). Something that I can think of is .takeUntil to wait to receive as many empty employee responses as concurrent calls you can have (this way you would make sure that all other responses are completed)

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.