Angular performance part 2
Tags: angular, webdev, beginners, stuartinhcity
Published: 2019-12-10 16:10:24

Part1 link on the comment section please have a look : )

22. Preload and Prefetch attribute: These attributes help to load the static resources as quickly as possible thus improving the time for first meaningful paint. Having faster first meaningful paint greatly affect the user experience. Preload and Prefetch are almost similar with the only difference is that Preload resources have greater priority. So use Preload for the assets which are essential for the initial rendering and use Prefetch for the resources which are required after site load (required in future across the pages).

23. Updating Third Party Packages: Make sure you are regularly updating your third party packages. Many times newer packages may contain many performance improvements including smaller size and other build time performance optimizations (e.g. RxJS 6). Also by regularly updating the packages, you may get many improvements related to the bug fixes, security vulnerability fixes, fixes related to package compatibility etc.

24. Compressing images: It’s a good idea to compress the images without losing much of the quality thereby saving the bytes transferred over the network improving the build time. There are many tools available to achieve this. VS Code extension called TinyPNG can be used to compress Jpeg and PNG images without losing much of the quality.

25. Remove unused fonts: It’s a good idea to remove the unused fonts which may help you save few bytes over the network.

26. Slow DNS and SSL: Sometimes your DNS and SSL provider could be the reason for slow load time. So make sure the DNS and SSL are fast and configured correctly.

Run Time Performance

27. Change Detection: By default on each asynchronous event, Angular performs a dirty checking by performing a change detection for the whole component tree. Such dirty checking could be a lot computation heavy for a medium to large apps. You can drastically reduce the change detection by setting “ChangeDetectionStrategy” to “OnPush”. The OnPush strategy promotes the use of immutable data structures.

28. Detach Change Detector: We can completely detach the component from change detection thereby giving a developer the control to inform Angular as to when and where to perform the change detection.

29. Web Workers: The JavaScript implementation in all browser is single threaded thus making the whole app to run on a single thread. Such single-threaded execution drastically reduces the frame rate of the complex application as both UI painting and JS execution handled by the same thread. As Angular by default avoids direct DOM manipulation, it is possible to run the entire Angular app in a separate web worker thread thereby keeping the main thread free to just handle the UI rendering. Check this post to see how to run an angular-cli app inside web worker. However, there are many npm packages that try to access DOM directly thereby creating issues while running the whole app inside the worker process. If you want to run only a piece of code under a web worker thread then look at this npm package.

30. Web assembly: Web assembly is a low-level assembly like a language enabling near-native performance. WebAssembly aims to execute at native speed by taking advantage of common hardware capabilities available on a wide range of platforms. You can take advantage of Webassembly to run some amount of your web app code with Web assembly. Take a look at this demo app created with angular-cli and wasm. However, you should be aware of the fact wasm is still new and using it sometimes may be tricky considering as of now it has only 4 supported data types (2 floating points and 2 integer points). Also as of now, for most of the cases, performance benefit of wasm is not that huge when you are using it to execute a small piece of code compared to inline JS. Properly evaluate which code you want to move to wasm.

31. trackBy: By default, *ngFor identifies object uniqueness by reference. If the object reference is broken by updating the content of the object, Angular removes 
the related DOM node completely and recreate it again even though the actual change required is for only a small part of the DOM node. This issue can be easily solved by using trackBy.

@Component({
    selector: 'app', 
    template: `<ul>
                    <li *ngFor="let item of items; trackBy: trackById">{{item.name}}</li>
               </ul>`
})
class AppComponent {
    Items = [
        {
            id: 1,
            name: 'item 1'
        }, {
            id: 2,
            name: 'item 2'
        },
        ...
    ];
    trackById(index, item) {

        return item.id;
    }
}


32. Pure Pipes: In the “@Pipe” decorator you can specify “pure” flag as true. This flag indicates that the pipe is not dependent on any outside or global state and is side effect free. This enables Angular to cache the outputs for all the input parameters the pipe has been invoked with and thus allows to reuse the values instead of recomputation. This can lead to a massive reduction in the duplicate operations performed in many cases thus hugely improving the performance.

33. Avoid complex computations in the template: Avoid doing complex calculation in the HTML template (ex calling some component method inside the template), instead leverage the use of pure pipes thereby taking advantage of Angular caching and hence avoiding duplicate operations or if the use of pipe is not possible, see the opportunity to pre-calculate the values and then directly bind values instead of calling the component method in the template.

34. enableProdMode: Invoking “enableProdMode()” avoids Angular from performing additional checks for change detection.

import {enableProdMode} from '@angular/core';
if (ENV === 'production') {
    enableProdMode();
}

35. AOT Compilation: AOT not only improves the build time performance but also the runtime performance of the app.

36. Optimize Events: Slower DOM events block change detection until the event is not completed. For example, if you have a click event in your template which is handled in the component and the component itself is calling service method to process it, the change detection will not complete until the control is not returned from the service. If your service is taking more time to perform the intended operation, then it will ultimately slow down the change detection. See the opportunity to optimize your logic to improve the duration or if possible try to move your service logic to separate web worker thread or use wasm if needed.

37. Unsubscribing Observables: Observables could create the memory leak issue. So it is better to unsubscribe them when they are not needed anymore. However, you don’t have to unsubscribe all the observables used. Unsubscribing explicitly is required when a subscription is created inside a component that is destroyed before the observable completes. Check this SO thread for more info.

38. Observable share() operator: If you have subscribed the observable at multiple locations/components, then each subscription will try to produce the data even though the data is duplicate. We can avoid the processing of the duplicate data across subscriptions using the “share()” operator.


import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs';
import {share} from 'rxjs/operators';
@Injectable()
export class AppService {
    data: Observable < any >;
    constructor(private http : HttpClient) {
        this.data = this.http.get<any> ('apiUrl').pipe(share());
    }
    getData() {
        return this.data;
    }
}

39. Progressive Web Apps: The PWA not just give you a load time optimization but also the runtime optimizations making your app more responsive, interactive, fast, smooth animations, offline support etc.

40. Updating Third-Party Packages: Again regularly updating your third party packages may also result in better run time performance.

41. console.log(): Using console.log() statements in your production code could be a bad idea as it will slow down the performance of the app and also logging objects with console.log() creates memory leak issue. When the browser’s console window is open, the console.log() execution slows down even further by many times thus impacting site’s performance significantly. It’s better to completely remove the console.log() statements from your production code or at least have an environment specific conditional logging.

42. Global Variables: There are many disadvantages of using global variables and one of them is the memory leak. The variables defined in the global scope won’t be cleared until the window is reloaded or tab is closed thus resulting in the memory leak if the global variable is not intended to be used throughout the app. If for some reason you want to have global variables, there are better ways to do it in the Angular.