Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Common Angular Gotcha Extended

Hong Tat
September 12, 2019

Common Angular Gotcha Extended

Knocking your head against unexpected issues while building your projects on Angular? We all did at some point!

In this talk, I will share about a few common mistakes that I've made (probably you as well!) when working in Angular and how to resolve or avoid them!

Hong Tat

September 12, 2019
Tweet

Other Decks in Programming

Transcript

  1. 1. To show a list of information in a table

    format. 2. Handle button click events 3. Refresh the table every second.
  2. The issues after the web app released ◎The web app

    crashed after a while they were using. ◎The users are not techies so they couldn’t provide me enough information. ◎No stack trace, no error message. 5
  3. 1. To show a list of information in a table

    format. 2. Handle button click events 3. Refresh the table every second.
  4. 1. To show a list of information in a table

    format. 2. Handle button click events 3. Refresh the table every second.
  5. Clear timeout var timerId = setTimeout(() => { /** Perform

    a task here.. */ }, 1000); clearTimeout(timerId); 15
  6. Clear timeout var timerId = setTimeout(() => { /** Perform

    a task here.. */ }, 1000); clearTimeout(timerId); 16
  7. Clear timeout var timerId = setTimeout(() => { /** Perform

    a task here.. */ }, 1000); clearTimeout(timerId); 17
  8. 1. To show a list of information in a table

    format. 2. Handle button click events 3. Refresh the table every second.
  9. 1. To show a list of information in a table

    format. 2. Handle button click events 3. Refresh the table every second.
  10. Second root cause – event binding var divElement = document.getElementById("myDIV");

    // Attach an event handler to <div> divElement.addEventListener("mouseclick", myFunction); 20
  11. Remove event binding var divElement = document.getElementById("myDIV"); // Attach an

    event handler to <div> divElement.addEventListener("mouseclick", myFunction); // Remove the event handler from <div> divElement.removeEventListener("mouseclick", myFunction); 21
  12. Remove event binding var divElement = document.getElementById("myDIV"); // Attach an

    event handler to <div> divElement.addEventListener("mouseclick", myFunction); // Remove the event handler from <div> divElement.removeEventListener("mouseclick", myFunction); 22
  13. Why memory leak happened? ◎You allocate memory in your application

    and forget to free it. ◎When you are finished with the memory but don’t allow garbage collector to clean it up. 23
  14. What condition causes memory leak? ◎The web application that runs

    for very long period of time. E.g., Facebook, enterprise application. 24
  15. What cause memory leak in Angular? ◎Subscribe to event listeners

    manually 25 this.renderer .listen('document', 'click', (evt) => { console.log('Clicking the document', evt); });
  16. What cause memory leak in Angular? ◎Subscribe to an observable

    26 this.httpClient.get<Config>(this.configUrl) .subscribe(() => { // do something }); this.route.data .subscribe(() => { // do something });
  17. How to prevent memory leak in Angular? ◎Unlisten the event

    listener ◎Unsubscribe manually ◎Using TakeUntil operator ◎Using Async pipe 27
  18. Unlisten the event listener unlistenFunction: () => void; ngOnInit(): void

    { this.unlistenFunction = this.renderer.listen( this.myButton.nativeElement, 'click', (evt) => { console.log('Clicking the button', evt); } ); // Add listeners } ngOnDestroy(): void { this.unlistenFunction(); // Remove listeners } 28
  19. Unlisten the event listener unlistenFunction: () => void; ngOnInit(): void

    { this.unlistenFunction = this.renderer.listen( this.myButton.nativeElement, 'click', (evt) => { console.log('Clicking the button', evt); } ); // Add listeners } ngOnDestroy(): void { this.unlistenFunction(); // Remove listeners } 29
  20. Unlisten the event listener unlistenFunction: () => void; ngOnInit(): void

    { this.unlistenFunction = this.renderer.listen( this.myButton.nativeElement, 'click', (evt) => { console.log('Clicking the button', evt); } ); } ngOnDestroy(): void { this.unlistenFunction(); // Remove listeners } 30
  21. Unlisten the event listener unlistenFunction: () => void; ngOnInit(): void

    { this.unlistenFunction = this.renderer.listen( this.myButton.nativeElement, 'click', (evt) => { console.log('Clicking the button', evt); } ); // Add listeners } ngOnDestroy(): void { this.unlistenFunction(); // Remove listeners } 31
  22. How to prevent memory leak? ◎Unlisten the event listener ◎Unsubscribe

    manually ◎Using TakeUntil operator ◎Using Async pipe 32
  23. Unsubscribe Manually routeData$: Subscription; ngOnInit() { this.routeData$ = this.route.data .subscribe(x

    => { // do something }); } ngOnDestroy() { this.routeData$.unsubscribe(); } 33
  24. Unsubscribe Manually routeData$: Subscription; ngOnInit() { this.routeData$ = this.route.data .subscribe(x

    => { // do something }); } ngOnDestroy() { this.routeData$.unsubscribe(); } 34
  25. Unsubscribe Manually routeData$: Subscription; ngOnInit() { this.routeData$ = this.route.data .subscribe(x

    => { // do something }); } ngOnDestroy() { this.routeData$.unsubscribe(); } 35
  26. Unsubscribe Manually routeData$: Subscription; ngOnInit() { this.routeData$ = this.route.data .subscribe(x

    => { // do something }); } ngOnDestroy() { this.routeData$.unsubscribe(); } 36
  27. How to prevent memory leak? ◎Unlisten the event listener ◎Unsubscribe

    manually ◎Using TakeUntil operator ◎Using Async pipe 39
  28. Using the TakeUntil operator private unsubscribe$ = new Subject<void>(); ngOnInit()

    { this.someService.getSomething1() .takeUntil(this.unsubscribe$) .subscribe(x => { }); this.someService.getSomething2() .pipe( takeUntil(this.unsubscribe$) ).subscribe(x => { }); } ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } 40
  29. Using the TakeUntil operator private unsubscribe$ = new Subject<void>(); ngOnInit()

    { this.someService.getSomething1() .takeUntil(this.unsubscribe$) .subscribe(x => { }); this.someService.getSomething2() .pipe( takeUntil(this.unsubscribe$) ).subscribe(x => { }); } ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } 41
  30. Using the TakeUntil operator private unsubscribe$ = new Subject<void>(); ngOnInit()

    { this.someService.getSomething1() .takeUntil(this.unsubscribe$) .subscribe(x => { }); this.someService.getSomething2() .pipe( takeUntil(this.unsubscribe$) ).subscribe(x => { }); } ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } 42
  31. Using the TakeUntil operator private unsubscribe$ = new Subject<void>(); ngOnInit()

    { this.someService.getSomething1() .takeUntil(this.unsubscribe$) .subscribe(x => { }); this.someService.getSomething2() .pipe( takeUntil(this.unsubscribe$) ).subscribe(x => { }); } ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } 43
  32. Using the TakeUntil operator private unsubscribe$ = new Subject<void>(); ngOnInit()

    { this.someService.getSomething1() .takeUntil(this.unsubscribe$) .subscribe(x => { }); this.someService.getSomething2() .pipe( takeUntil(this.unsubscribe$) ).subscribe(x => { }); } ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } 44
  33. Using the TakeUntil operator private unsubscribe$ = new Subject<void>(); ngOnInit()

    { this.someService.getSomething1() .takeUntil(this.unsubscribe$) .subscribe(x => { }); this.someService.getSomething2() .pipe( takeUntil(this.unsubscribe$) ).subscribe(x => { }); } ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } 45
  34. Using the TakeUntil operator private unsubscribe$ = new Subject<void>(); ngOnInit()

    { this.someService.getSomething1() .takeUntil(this.unsubscribe$) .subscribe(x => { }); this.someService.getSomething2() .pipe( takeUntil(this.unsubscribe$) ).subscribe(x => { }); } ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } 46
  35. Using the TakeUntil operator private unsubscribe$ = new Subject<void>(); ngOnInit()

    { this.someService.getSomething1() .takeUntil(this.unsubscribe$) .subscribe(x => { }); this.someService.getSomething2() .pipe( takeUntil(this.unsubscribe$) ).subscribe(x => { }); } ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } 47
  36. How to prevent memory leak? ◎Unlisten the event listener ◎Unsubscribe

    manually ◎Using TakeUntil operator ◎Using Async pipe 48
  37. What is Async Pipe? ◎Allows observables to be used in

    a template. ◎Takes care of the subscription to the observable and the unsubscription as well. 49
  38. Without Async Pipe weathers$: Subscription; weathers: Weather[]; ngOnInit() { this.weathers$

    = this.weatherService .getWeathers() .subscribe(x => { this.weathers = x; }); } ngOnDestroy() { this.weathers$.unsubscribe(); } 50
  39. Without Async Pipe weathers$: Subscription; weathers: Weather[]; ngOnInit() { this.weathers$

    = this.weatherService .getWeathers() .subscribe(x => { this.weathers = x; }); } ngOnDestroy() { this.weathers$.unsubscribe(); } 51
  40. Without Async Pipe weathers$: Subscription; weathers: Weather[]; ngOnInit() { this.weathers$

    = this.weatherService .getWeathers() .subscribe(x => { this.weathers = x; }); } ngOnDestroy() { this.weathers$.unsubscribe(); } 52
  41. Without Async Pipe weathers$: Subscription; weathers: Weather[]; ngOnInit() { this.weathers$

    = this.weatherService .getWeathers() .subscribe(x => { this.weathers = x; }); } ngOnDestroy() { this.weathers$.unsubscribe(); } 53
  42. Without Async Pipe weathers$: Subscription; weathers: Weather[]; ngOnInit() { this.weathers$

    = this.weatherService .getWeathers() .subscribe(x => { this.weathers = x; }); } ngOnDestroy() { this.weathers$.unsubscribe(); } 54
  43. Without Async Pipe weathers$: Subscription; weathers: Weather[]; ngOnInit() { this.weathers$

    = this.weatherService .getWeathers() .subscribe(x => { this.weathers = x; }); } ngOnDestroy() { this.weathers$.unsubscribe(); } 55
  44. Without Async Pipe weathers$: Subscription; weathers: Weather[]; ngOnInit() { this.weathers$

    = this.weatherService .getWeathers() .subscribe(x => { this.weathers = x; }); } ngOnDestroy() { this.weathers$.unsubscribe(); } 56
  45. Why is a web app loading slow? ◎Slow internet connection.

    ◎The initial files to run the web application are too big. ◦ Third party plugins ◦ Images
  46. Angular Budgets ◎Allows us to configure expected sizes of these

    bundles. ◎To set budget thresholds to ensure parts of your application stay within boundaries. 63
  47. Angular budgets configuration // angular.json { "configurations": { "production": {

    "budgets": [{ "type": "initial", "maximumWarning": “1mb", "maximumError": “2mb" }] } } } 64
  48. How to reduce a web application loading time? ◎ng build

    + Prod flag ◎Angular Routing: Lazy loading ◎Angular Routing: Pre loading 66
  49. ng build + Prod flag ◎ng build --prod enables various

    build optimizations 67 --dev --prod Uglify No Yes + merge vendor chunk to main chunk Source Maps Yes No CSS Resources Extraction No Yes Bundling & Tree-shaking No Yes
  50. 68

  51. How to reduce a web application loading time? ◎Prod flag

    ◎Angular Routing: Lazy loading ◎Angular Routing: Pre loading 69
  52. Angular Routing: Lazy Loading ◎Design pattern that loads the NgModules

    as needed. ◎It will split the js and style files into multiple bundles by module and load it when needed. ◎Keep the initial bundle sizes smaller. 70
  53. Lazy loading 71 Launch application Download main modules Template appears

    Navigate to a lazy loaded feature Download lazy loaded module Template appear Smaller file size
  54. How to reduce a web application loading time? ◎Prod flag

    ◎Angular Routing: Lazy loading ◎Angular Routing: Pre loading 75
  55. What is pre-loading in Angular routing ◎Pre-load lazy-loadable modules in

    the background after the application is bootstrapped. ◎This eliminates the possible latency when navigating to a lazy loaded module.
  56. Angular Routing: Pre loading 77 Launch application Download main modules

    Template appears Preload modules Navigate to a lazy loaded feature Template appear