HI WELCOME TO SIRIS

Angular promises vs observables

Leave a Comment

In Angular 2, to work with asynchronous data we can use either Promises or Observables. In our previous videos in this series, we discussed using both Observables and Promises. There are several differences between Promises and Observables. In this video let's discuss these differences.


As a quick summary the differences are shown in the table below
PromiseObservable
Emits a single valueEmits multiple values over a period of time
Not LazyLazy. An Observable is not called until we subscribe to the Observable
Cannot be cancelledCan be cancelled using the unsubscribe() method
Observable provides operators like map, forEach, filter, reduce, retry, retryWhen etc.


A Promise emits a single value where as an Observable emits multiple values over a period of time. You can think of an Observable like a stream which emits multiple items over a period of time and the same callback function is called for each item emitted. So with an Observable we can use the same API to handle asynchronous data whether that data is emitted as a single value or multiple values over a period of time.

A Promise is not lazy where as an Observable is Lazy. Let's prove this with an example. Consider this method getEmployeeByCode() in employee.service.ts. Notice this method returns an Observable.

getEmployeeByCode(empCode: string): Observable<IEmployee> {
    return this._http.get("http://localhost:31324/api/employees/" + empCode)
        .map((response: Response) => <IEmployee>response.json())
        .catch(this.handleError);
}

Here is the consumer code of the above service. In our example, this code is in employee.component.ts in ngOnInit() method. Notice we are subscribing to the Observable using the subscribe() method. An Observable is lazy because, it is not called and hence will not return any data until we subscribe using the subscribe() method. At the moment we are using the subscribe() method. So the service method should be called and we should receive data.

ngOnInit() {
    let empCode: string = this._activatedRoute.snapshot.params['code'];

    this._employeeService.getEmployeeByCode(empCode)
        .subscribe((employeeData) => {
            if (employeeData == null) {
                this.statusMessage =
                    'Employee with the specified Employee Code does not exist';
            }
            else {
                this.employee = employeeData;
            }
        },
        (error) => {
            this.statusMessage =
                'Problem with the service. Please try again after sometime';
            console.error(error);
        });
}

To prove this 
1. Launch Browser developer tools by pressing F12 while you are on the browser. 
2. Navigate to /src/employees/emp101
3. Click on the Network Tab
4. In the Filter textbox, type "api/employees"
5. At this point, you should only see the request issued to EmployeeService in the table below
6 Hover the mouse over "emp101" under "Name" column in the table
7. Notice the request to employee service (/api/employees/emp101) is issued

lazy observable

Instead of hovering over the request, if you click on it, you can see the response data as shown below. Make sure you select the "preview" tab.

lazy observablecollection

Now in employee.component.ts file, comment the subscribe() method code block as shown below. Notice we are still calling the getEmployeeByCode() method of the EmployeeService. Since we have not subscribed to the Observable, a call to the EmployeeService will not be issued over the network.

ngOnInit() {
    let empCode: string = this._activatedRoute.snapshot.params['code'];

    this._employeeService.getEmployeeByCode(empCode)
        //.subscribe((employeeData) => {
        //    if (employeeData == null) {
        //        this.statusMessage =
        //            'Employee with the specified Employee Code does not exist';
        //    }
        //    else {
        //        this.employee = employeeData;
        //    }
        //},
        //(error) => {
        //    this.statusMessage =
        //        'Problem with the service. Please try again after sometime';
        //    console.error(error);
        //});
}

With the above change in place, reload the web page. Notice no request is issued over the network to the EmployeeService. You can confirm this by looking at the network tab in the browser developer tools. So this proves that an Observable is lazy and won't be called unless we subscribe using the subscribe() method.

Now, let's prove that a Promise is NOT Lazy. I have modified the code in employee.service.ts to return a Promise instead of an Observable. The modified code is shown below.

getEmployeeByCode(empCode: string): Promise<IEmployee> {
    return this._http.get("http://localhost:31324/api/employees/" + empCode)
        .map((response: Response) => <IEmployee>response.json())
        .toPromise()
        .catch(this.handlePromiseError);
}

Here is the consumer code of the above service. In our example, this code is in employee.component.ts in ngOnInit() method. 

ngOnInit() {
    let empCode: string = this._activatedRoute.snapshot.params['code'];

    this._employeeService.getEmployeeByCode(empCode)
        .then((employeeData) => {
            if (employeeData == null) {
                this.statusMessage =
                    'Employee with the specified Employee Code does not exist';
            }
            else {
                this.employee = employeeData;
            }
        },
        (error) => {
            this.statusMessage =
                'Problem with the service. Please try again after sometime';
            console.error(error);
        });
}

Because a promise is eager(not lazy), calling employeeService.getEmployeeByCode(empCode) will immediately fire off a request across the network to the EmployeeService. We can confirm this by looking at the network tab in the browser tools. 

Now you may be thinking, then() method in this case is similar to subscribe() method. If we comment then() method code block, will the service still be called. The answer is YES. Since a Promise is NOT LAZY, Irrespective of whether you have then() method or not, calling employeeService.getEmployeeByCode(empCode) will immediately fire off a request across the network to the EmployeeService. You can prove this by commenting then() method code block and reissuing the request.

0 comments:

Post a Comment

Note: only a member of this blog may post a comment.