Oct 28, 2018

Angular - Best Practices

Using Immutability

Generally speaking, immutability is a good practice in JavaScript whether we are using Angular or not, so the recommendation to prefer immutability is a good recommendation in all JavaScript code. In general, do not mutate existing objects in memory, but rather create new objects. Using immutability can help you avoid certain classes of bugs, such as bugs that occur when a value is unexpectedly changed from somewhere else in the code. Using immutability can also help with certain types of change detection in Angular. Refer following for safe way of deep copying an object.
function cloneObject(obj) {
    var clone = {};
    for(var i in obj) {
        if(obj[i] != null &&  typeof(obj[i])=="object")
            clone[i] = cloneObject(obj[i]);
        else
            clone[i] = obj[i];
    }
    return clone;
}
let newObj = JSON.parse(JSON.stringify(obj));

copy via object assign

Following will do shallow copy, left most is target. value in right will override argument in left.
Object.assign({},employee,{name:'New Name'}, {age:10})

copy via spread

const copyObject = {...objtobecloned, {name:'New Name'}}
const copyArray = [...arrayToBeCopied, ]

map, filter, reduce, concat, spread mutate the array where as push, pop, reverse are immutable.

You can also use library like Immer.

Callback hell

When writing callback keep an eye on a number of curly braces as it gets difficult to manage if you have deeply nested callback. It's sometimes neat to put callback (if it's getting bigger) in a separate function.

Prefixing Component Selectors

Prefixing your component selectors will avoid conflicts if you happen to import a module that has a component selector that conflicts with one of your own.

Delegating Complex Logic to Services

Inside component, you mostly initialize form controls, add validators, redirect logic, event handler, etc, any business logic or complex processing should be in service. On the other hand, service should not have to deal with form controls objects.

Code Organization

Properties at the top followed by the constructor, followed by interface implementation, followed by the component public method and at the end private method. Implement Life Cycle Hook Interfaces like OnInit, OnChange.

Service Injector Best Practices


For every Angular app, Angular creates a root injector, which is responsible for injecting services wherever they're needed. If you provide a service in the eagerly loaded module, then angular register that with the root injector which makes it (singleton) available to the entire application. On the other hand, if you provide a service in a lazily-loaded feature module, Angular creates a new injector for that module and registers it there. So the instance of the service is only available to that lazily-loaded feature module. This behavior of creating a second instance is unique to lazily-loaded feature modules. Just remember that if you provide a service in a lazily-loaded module, it is only available to that module, and if you need a single instance of a service to be available everywhere, define it in your core module.

Ahead-of-time Compilation and tree shaking CLI

Use cli to build

Lazy Loading Feature Modules

Modules are not downloaded at the launch of the application rather only eagerly loaded module is downloaded. There are three type -
 Lazy Loading - Module is downloaded only when the user navigates to lazily loaded feature.
 Preloading - At the launch of application only eagerly loaded module is downloaded and hence user is severed quickly. Once downloaded and template appears, router checks for preloaded module and download them. This way
 application launch becomes fast as at that time user is downloading only eagerly loaded module and once user is served, angular downloads feature module, so its available for user when user try's to navigate to it.
 Custome Preloading - You can put custom rule to defined preloading behavior.

Monitoring Bundle Sizes


It's very important to keep an eye on the bundle size of all the chunks which gets created during build. You can use source-map-explorer to peek into your bundle to see whats taking most of the space. Ultimately user will be downloading these bundles and smaller the bundle size faster it would be to download
 ng build --prod --source-map

Improving Performance with OnPush Change Detection

Application state change can be caused by three things - Events (click, submit, ), XHR (http call), Timer (setTimeout, setInterval). These are the asynchronous operations which triggers change detection. So when change detection is triggered each of bindings will be evaluated, which can cause performance concern on a page which has lots of binding. So if you don't expect any of your binding to get impacted then you may add OnPush so that bindings are not re-evaluated on events, xhr or timer. To test add following <div>{{callMethod()}}</div> to your template and you will notice that callMethod will be called everytime an event is fired on the component or http call happens.

Pure and Impure Pipe Performance

A pure pipe is only called when Angular detects a change in the value or the parameters passed to a pipe. An impure pipe is called for every change detection cycle no matter whether the value or parameters changes. So in case of pure pipe, when you pass an array and one of the element of array changes, the pure pipe will not be called as the instance remain the same. So if you have sort custom pipe (pure) which takes an array, the pipe will not be executed if you update one of the element of the array

No comments:

Post a Comment