0

Angular best Practices

Mở đầu

Angular được coi là một trong những framework Javascript nổi bật nhất để phát triển các ứng dụng web và mobile. Angular được phát triển bởi các kỹ sư tại Google và được duy trì bởi chính Google.

Trong suốt phát triển ứng dụng Angular, mình đã đúc kết được 1 số kinh nghiệm giúp code clean hơn và code dễ maintaince, cũng như đảm bảo performance của ứng dụng

Bài viết này chia sẻ 1 số kinh nghiệm cá nhân, cũng như 1 số kiến thúc mình tìm kiếm được trên mạng. Hy vọng nhưng chia sẻ dưới đây sẽ giúp các bạn phát triển ứng dụng angular tốt hơn

Các bài học

Sử dụng trackBy thay vì ngFor

ngFor là 1 directive tích hợp sẵn trong Angular, ngFor được dùng để loop các phần tử trong 1 mảng. Chúng ta nên sử dụng trackBy thay cho ngFor, khi sử dụng ngFor khi mảng có sự thay đổi DOM sẽ được rendered lại toàn bộ thay vào đó khi sử dụng trackBy Dom chỉ thay đổi thành phần được thay đổi (không phải tất cả DOM)

<ul>
  <li *ngFor="let item of collection;">{{item.id}}</li>
</ul>

Sẽ thay đổi toàn bộ DOM khi collection được thay đổi

@Component({
  selector: 'my-app',
  template: `
    <ul>
      <li *ngFor="let item of collection;trackBy: trackByFn">{{item.id}}</li>
    </ul>
    <button (click)="getItems()">Refresh items</button>
  `,
})
export class App {

  constructor() {
    this.collection = [{id: 1}, {id: 2}, {id: 3}];
  }
  
  getItems() {
    this.collection = this.getItemsFromServer();
  }
  
  getItemsFromServer() {
    return [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
  }
  
  trackByFn(index, item) {
    return index; // or item.id
  }
}

Chỉ thay đổi DOM li khi collection được thay đổi

Sử dụng module Lazy loading

Lazy loading là 1 tính năng được tính hợp sẵn trên angular. Khi sử dụng module này thay vì load tất cả các thành phần, ta chỉ cần load những thứ mà chúng ta cần và bỏ qua các thành phần khác không cần thiết.

// app.routing.ts
{
path: 'lazy-load',
loadChildren: 'lazy-load.module#LazyLoadModule'
}
// lazy-load.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { LazyLoadComponent }  from './lazy-load.component';
@NgModule({
imports: [
CommonModule,
RouterModule.forChild([
{
path: '',
component: LazyLoadComponent
}
])
],
declarations: [
LazyLoadComponent
]
})
export class LazyModule {}

CDK Virtual Scroll

CDK Virtual Scroll là một công cụ rất quan trọng mà bạn có thể sử dụng để đạt được hiệu suất tốt trong quá trình phát triển ứng dụng của mình. Nếu bạn cần hơn một nghìn phần tử hiển thị cùng một lúc, điều đó sẽ khả năng làm chậm ứng dụng của bạn, cũng như khiến ứng dụng của bạn dễ bị tấn công hơn. CDK Virtual Scroll có thể nâng cao hiệu suất của ứng dụng và làm việc tốt với các dữ liệu lớn. Dưới đây là 1 ví dụ về cách hoạt động của CDK

1. Import CDK Virtual Scroll vào ứng dụng của bạn app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

import { ScrollingModule } from '@angular/cdk/scrolling';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ScrollingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

2. Tạo 10000 dữ liệu app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  numbers: number[] = [];

  constructor() {
    for (let index = 0; index < 10000; index++) {
      this.numbers.push(index);
    }
  }
}

3. Render data app.component.html

<h1 class="center">Virtual Scroll using Angular 7</h1>

<ul class="list">
  <cdk-virtual-scroll-viewport  style="height: 500px" itemSize="90" >
    <ng-container *cdkVirtualFor="let n of numbers">
      <li> {{n}} </li>
    </ng-container>
  </cdk-virtual-scroll-viewport>
</ul>

4. Thêm css

max-width: 500px;
    color: #333;
    list-style: none;
    margin: 50px auto;
    padding: 10px;
}

.list li {
    padding: 25px;
    background: #FAFAAF;
    border-radius: 5px;
    margin-bottom: 5px;
    text-align: center;
    font-size: 32px;
    font-weight: 600;
}

.center {
    text-align: center;
}

Bây giờ bạn hay theo dõi performance thay đổi như thế nào khi sử dụng ScrollingModule

Angular Coding Styles

Việc tuân thủ theo coding styles luôn luôn là điều cần thiết. Viết code theo chuẩn sẽ dễ dàng maintaince, debug và fix bug về sau, đồng thời việc phát triển ứng dụng cũng dễ dàng hơn khi bạn tuân thủ 1 chuẩn coding.

Bạn có thể tham khảo coding style chuẩn ở đây https://angular.io/guide/styleguide

Cấu trúc folder trong Angular

Tạo cấu trúc thư mục là một yếu tố cực kỳ quan trọng mà bạn nên cân nhắc trước khi bắt đầu dự án của mình. Nếu bạn chưa cấu trúc thư mục đúng cách, bạn đã gặp phải rất nhiều vấn đề luôn ám ảnh bạn trong suốt quá trình phát triển của mình.

Cho dù đó là dự án quy mô vừa và lớn, bạn sẽ gặp rất nhiều thay đổi trong giai đoạn phát triển và dự án của bạn sẽ dễ dàng thích ứng với những thay đổi mới được thực hiện trong giai đoạn phát triển.

Bạn có thể tham khảo cấu trúc folder dự án sau: https://viblo.asia/p/angular-folder-structure-in-project-m68Z04DdZkG

Prevent memory leaks khi sử dụng Angular Observable

Memory leaks rất phổ biến và được thấy trong mọi ngôn ngữ lập trình, thư viện hoặc framework. Angular không phải là ngoại lệ cho điều đó. Observables trong Angular rất hữu ích vì nó đồng bộ dữ liệu của bạn, nhưng rò rỉ bộ nhớ là một trong những vấn đề rất nghiêm trọng có thể xảy ra nếu bạn không để ý. Nó có thể tạo ra tình huống tồi tệ nhất trong quá trình phát triển. Dưới đây là một số tips sau đây để tránh rò rỉ.

1. Sử dụng ‘async pipe’:

Việc sử dụng ‘async pipe’ là rất quan trọng đổi với các observable, bên cạnh đó bạn cũng nên hạn chế subscribe các observable để hạn chế việc không kiểm soát được chúng dẫn đến memory leaks

2. Sử dụng ‘take(1)’: ‘take(1)’ là 1 toán tử cho phép ta chỉ lấy duy nhất 1 phần tử , đồng thời không subscribe khi gặp giá trị mới. Điều đó đảm bảo quá trình subscribe chỉ có 1 lần duy nhất, điều đó đảm bảo quá trình bảo mật cũng như tránh rò rỉ bộ nhớ

data$.pipe(take(1)).subscribe(res=>console.log(res))

3. Sử dụng ‘takeUntil’: ‘takeUntil’ là 1 toán tử được sử dụng khi muốn theo dõi các Observables và xử lý subscribe sau khi Observables thay đổi giá trị hoặc được hoàn thành

export class SimpleComponent implements OnInit, OnDestroy {
 constructor(private route: ActivatedRoute,
             private http: Http) {
 }
 ngOnInit() {
   this.route.params
     .takeUntil(componentDestroyed(this))
     .subscribe(params => {
       // do something
     });
   this.http.get("/load")
     .takeUntil(componentDestroyed(this))
     .subscribe(result => {
       // do something
     });
 }
 ngOnDestroy() {
   // empty
 }
}

Sử dụng ES6

1. ‘let and const’ thay cho ‘var’

Sử dụng khai báo biến let và const thay cho var để đảm bảo chúng ta không gặp phải các vấn đề đổi với var

let temp;
Const pi = 3.14159

2. Spread Operator Chúng ta nên sử dụng toán tử (...) trong array và object, việc sử dụng toán tử này khiến code trở nên ngắn gọn và dễ đọc

Array

const items = ['This', 'is', 'a', 'sentence'];

console.log(items) // Line 1

console.log(...items) // Line 2

// [ 'This', 'is', 'a', 'sentence' ] // Output 1

// This is a sentence // Output 2

Object

const obj = { name: 'Foo', age: 22 };

const newObj = { ...obj }

console.log(newObj)

// { name: 'Foo', age: 22 }

Khai báo kiểu biến thay vì dùng ‘any’

Trong quá trình phát triển dự án angular, các lập trình viên thưởng khai báo biến kiểu 'any' vì tính tiện dụng của nó. Nếu bán không gán giá trị cho biến này, hệ thống sẽ gán 1 giá trị nào đó. Điều này sẽ gây ra khó khăn khi ứng dụng của bạn đã trở nên phức tạp

Nếu bạn code như sau thì input của bạn phải thật đúng, trong 1 số trường hơp nó sẽ gây ra output không đúng

const x = 1;

const y = 'a';

const z = x + y;

console.log(`Value of z is: ${z}`

// Output

Value of z is 1a

Thay vào đó chúng ta nên viết code như sau, để đảm bảo ouput được đúng đắn

const x: number = 1;

const y: number = 'a';

const z: number = x + y;

// This will give a compile error saying:

Type '"a"' is not assignable to type 'number'.

const y: number

Kết luận

Trên đây là nhưng bài học mà mình đã rút ra được trong quá trình phát triển dự án angular. Quá trình phát triển ứng dụng là luôn luôn thay đổi, có thể những bài học này là đúng hôm nay nhưng ngày mai nó lại không đúng, chúng ta cần phải luôn luôn cập nhật và phát triển để cho ứng dụng ngày càng tốt hơn


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí