Pranay Rana: June 2018

Saturday, June 30, 2018

Different Kind of for loop construct in JavaScript/TypeScript

For Loop is very basic type of loop exist in all programming language. For loops allows to go over each items in iterable objects and allows to access each item of iterable objects. Each programming language provide different type of for loop to achieve purpose of iterating over iterable object and access each element to perform operation.

All programming language provide for loop (for(int i=0; i< array.length; i++)) i.e. indexed based and ForEach ( foreach(var ele in array)) i.e. element base.

But JavaScript/ TypeScript provides different type of for loops apart from basic once. Below are 4 different kind of JavaScript/ TypeScript

1. for
One of the most used and basic for loop to allows iterate block of code for predefined number.

Syntax
for (statement 1; statement 2; statement 3) {
    code block to be executed
}

Example code :
const array = [1,10,6,45,32];
for(let i=0;i< array.length;i++) {
 console.log(array[i]);
}

Above code shows one example how to use it, code prints each array item by rotating from 0 up to array length. Above example made using array of numbers but in real application one can create for loop just by setting numbers and execute block of code repeatedly for predefined numbers. So this loop is not restricted for iterables only.

2. for..of
allows to go over each item in iterable (Ex. like array, string, Map, Set, etc.)

Syntax
for (variable of iterable) {
  statement
}

Example code :
const array = [1,10,6,45,32];
for (const element of array) {
 console.log(element);
}

Above code does same thing as for loop code discussed above, go though each element of array and print.
But difference is for...of loop works only on the iterable objects and for each element of iterable, where as in basic for loop one externally need to set predefined number like from and to to execute block of code. So it helpful when want to execute on each element or by using each element of iterable.

Angular framework also have structural directive calle *ngFor for displaying data. Read more : Dynamic Html Structure with - *ngIf, *ngFor & ngSwitch

3. For In
allows to iterate over each property of object. This loop is different then other loops as it allows to go though object properties.

Syntax
for (variable in object) {
}

Example code:
const obj = { a : 1, b: 'Xyz', c:'123'};
for(let prop in obj) {
 console.log(prop +' : '+  obj[prop]);
}

code above prints each object property and value of it. Below is use cases when for..in very helpful.
  • Loop is useful when object structure is unknown (When object received as response from external api http call) and there is need of go through each property of object and display it.
  • It also useful when there is indexed (interface, class) object in type script and there is need of go through each indexed item without knowing key.
    Example:
    interface Product {
        [key: number]: string;
    }
    
    let products : Product = { };
    products[10]='xyz';
    products[20]='abc';
    
    for(let key in products) {
     console.log(key + ' : ' + products[key]);
    } 

4.  forEach(ele=> {} );
allows to iterate over each item in array and  execute function for each element in iterable.

Syntax
arr.forEach(function callback(currentValue[, index[, array]]) {
    //your iterator
}[, thisArg]);

Example code:
const array = [1,10,6,45,32];
array.forEach((element,index)=> {
 console.log(index +' ' +element);
});

Above code execute function for each element of array and prints element value & index of element in array.
Different from basic for is,  execute function for each element without knowing size of iterable & improves redability and difference from and for..of  is also allows to get index of each element which is not possible in for..of.

Wrapping up
Javascript/typescript provides 4 different which can be useful in different way based on simplicity & redablity of code , performance of loop and sometimes based on situation like for..in used for go through each property of object or each index of indexed class/interface.. 

Tuesday, June 12, 2018

Way to handle Parallel Multiple Requests

In web application Multiple requests means when there is need of making more then one Http requests to get result response and display to end user on web page. Multiple requests can be
  • Dependent Request
    Http Request is dependent request when it waits for result which needs to be given by other Http request i.e. parent request. Read more about how to perform Dependent request in angular here : Angular Dependent Request
  • Parallel Request
  • When client code fire more then one Http request on server and that all fired request get executed on server simultaneously.
Parallel Http requests are required when application need to make simultaneously to get data and display result to end user. For Example - In online shopping application, on order history page when use clicks on old Order to get detail , details page should display order details with all products detail which is associated with order.
Mostly in application database when order get saved its will save order details with associated product ids not full product. so to achieve this requirement once order data available with product ids, client code need to get fire multiple requests basically for each product id to get detail of product associated with order.

Below picture shows how parallel request get executed by approach going to discuss below.




Below are the way client code make parallel Http request and handle response of the requests to display final result with help of RxJs functions.

1. MergeMap

RxJs function mergeMap allows to fire out multiple request and handle response of each request to produce result. Function flatten inner observable(s) and allow to control each observable. Read more : MergeMap

    import { mergeMap, catchError } from 'rxjs/operators'; 
    megeMapTest() {
    const prouctIds: number[] = [1, 2, 3];
    const requests = from(prouctIds)
      .pipe(
      mergeMap(id => this.productService.getProduct(id))
      );

    requests.subscribe(
      data => console.log(data), //process item or push it to array 
      err => console.log(err));
 } 

In above code, important thing to note out is mergeMap, it merges all parallel requests fired to get product in one observable stream (array of observable) and then allows that request to handle individually.


Advantage
a. One of the advantage with mergemap is, it create single stream of observable and allows to process response of each request individually.
So if there is any request fails i.e. throws server side error, then it doesn't affect other parallel requests. Failed request(s) call error function in above code and succeeded request calls success function. (Which is advantage over second approach i.e. forkJoin function discussed below)

b. mergmap function start processing request as it get response i.e. in case of multiple parallel request it process request which completes first ,doen't wait for other request to get completed. (Which is advantage over second approach i.e. forkJoin function discussed below)

Disadvantage
a. It doesn't preserve sequence (i.e. order in which it fire) of requests, means if there are 10 request fired parallelly then which request complete first will display result first.

Solution to this is

    import { mergeMap, catchError } from 'rxjs/operators'; 
    list: Product[] = [];
    megeMapTest() {
    const prouctIds: number[] = [1, 2, 3];
    const requests = from(prouctIds)
      .pipe(
      mergeMap(id => this.productService.getProduct(id))
      );

      requests.subscribe(
      data => {
        this.list.push(data);

        this.list.sort((a: Product, b: Product) => {
          const aIndex = prouctIds.findIndex(id => id === a.Id);
          const bIndex = prouctIds.findIndex(id => id === b.Id);
          return aIndex - bIndex;
        });
      }, //process item or push it to array 
      err => console.log(err));
 } 

above solution code sort order of received response using index of array.

b. megeMap only merge request of same return type only. To understand this have look to above code again, all request is going to return observable of Product type which is going to be return by getProduct method of productservice.

Making use of forkJoin function can resolve this issue. Which is second approach discussed below.

2. ForkJoin

RxJs function forkJoin take one or more observable as input and provide steam of observable as result, which contains value last value emitted by each  inputted observable to function. Read more : forkJoin

import { catchError } from 'rxjs/operators';
import { of } from 'rxjs/observable/of';
import { forkJoin } from 'rxjs/observable/forkJoin';
  forkJoinTest() {
    const prouctIds: number[] = [1, 2, 3];
    const productRequests = prouctIds.map(id => this.productService.getProduct(id).pipe(
      catchError(error => of(`Bad Promise: ${error.message}`))
    ));

    const requests = forkJoin(productRequests);
    requests.subscribe(
      data => console.log(data) //process item or push it to array 
    );
  } 

In above code, as per definition forkJoin takes observable requests as input and returns result.

Advantage
a. forkJoin  reserve sequence (i.e. order in which request sent), so order in which requests inputted to forkJoin in same order it gives response result.

b. forkJoin can take multiple request which returns different type observable.

async forkJoinTest() {
    const customerRequest =this.customerService.getCustomer(1).pipe(
      catchError(error => of(`Bad request: ${error.message}`))
    );    
    const orderRequest =this.orderService.getOrder(1).pipe(
      catchError(error => of(`Bad request: ${error.message}`))
    ); 
    const productRequest =this.productService.getProduct(1).pipe(
      catchError(error => of(`Bad request: ${error.message}`))
    );

    const requests = await forkJoin(customerRequest,orderRequest,productRequests).toPromise();
    
    console.log('Customer ' + requests[0]);
    console.log('order ' + requests[1]);
    console.log('product ' + requests[2]);
  } 

In above code , forkJoin takes three requests (customer, product, order) which returns different type of observable. Also code make use of async/await advance typescript/javascript concept, which allows to wait till request completes. (Which is advantage over first approach i.e. mergeMap function discussed below)

Disadvantage
a. forkJoin waits for all inputted Http requests to get completed before calling subscribe function. So even though some request get completed it has to wait till other or lets say last request to complete. (This can be avoided with mergeMap function as it process requests as it get completed).

b. if one of the inputted request to forkJoin fails , then forkJoin also fails and return error even other inputted request completed successfully. To check run code as below and return error from server

import { catchError } from 'rxjs/operators';
import { of } from 'rxjs/observable/of';
import { forkJoin } from 'rxjs/observable/forkJoin'; 
  forkJoinTest() {
    const prouctIds: number[] = [1, 2, 3];
    const productRequests = prouctIds.map(id => this.productService.getProduct(id));

    //.pipe(
    //catchError(error => of(`Bad Promise: ${error.message}`))
    //));

    const requests = forkJoin(productRequests);
    requests.subscribe(
      data => console.log(data), //process item or push it to array
      err => console.log(err) 
    );
  } 

In above code catchError function is commented, that means if any of request fails then forkJoin also fails and return that error. (this is not case with mergeMap)
To avoid the make use of catchError function as given in above code.

Which one is better
Both of them is not good or not bad. It all depends on requirement at the end. Because there might be case when have requirement to wait for all request to complete or want to parallely executed request which return different value or do not want to produce result if one of sent requests fails then go for forkJoin and there might be case when have requirement for do not wait till all request get compete or do not want to reserve order of request or want to process requests even one of the request fails then go for mergeMap.