فریم ورک Angular که توسط گوگل توسعه یافته است، یک چارچوب قدرتمند برای برنامه نویسی پویای Single Page Application بر اساس TypeScript است.
این یک چارچوب ساختاریافته است نه یک کتابخانه مانند React ، بنابراین توسعه دهندگان باید مثل Angular « فکر کنند ». در پشت صحنه، از بلوکهای سازنده زیادی استفاده میکند: ماژولها، کامپوننت ها، data binding، سرویس ها، directivesها و موارد دیگر. این مقاله می خواهد بهترین شیوه های Angular را برای اجرای بهینه با رعایت قوانین ساده توضیح دهد.
چه : همیشه از Angular CLI برای ایجاد و مدیریت پروژه های Angular خود استفاده کنید.
چرا : Angular CLI یک راه استاندارد و کارآمد برای bootstrap، توسعه، آزمایش و استقرار برنامه های Angular ارائه می دهد.
چگونه :
# Install Angular CLI globally (if not already installed) npm install -g @angular/cli # Create a new Angular project ng new my-angular-app # Navigate to the project directory cd my-angular-app # Generate a component ng generate component my-component # Run the development server ng serve
چه : هر کامپوننت، سرویس یا ماژول باید یک مسئولیت واحد داشته باشد.
چرا : SRP قابلیت نگهداری، خوانایی و استفاده مجدد کد را ارتقا می دهد. درک و اشکال زدایی کد شما را نیز آسان تر می کند.
چگونه :
// Example of a component with a single responsibility import { Component } from '@angular/core'; @Component({ selector: 'app-user', template: '<div>{{ user.name }}</div>', }) export class UserComponent { user = { name: 'Marco Martorana' }; }
چه : از ChangeDetectionStrategy.OnPush
برای بهینه سازی change detection در کامپوننت ها استفاده کنید.
چرا : change detection OnPush تعداد بررسی ها را کاهش می دهد و عملکرد را به خصوص در برنامه های بزرگ افزایش می دهد.
چگونه :
import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ selector: 'app-user', template: '<div>{{ user.name }}</div>', changeDetection: ChangeDetectionStrategy.OnPush, }) export class UserComponent { user = { name: 'Marco Martorana' }; }
چه : از فرمهای Reactive انگولار همراه با form validationها استفاده کنید.
چرا : Angular دو نوع مختلف فرم را ارائه می دهد: Template Driven و فرم های Reactive . یک فرم Reactive روشی با قابلیت پیش بینی و مدیریت بیشتری برای مدیریت داده های فرم، از جمله اعتبار سنجی و عملیات async ارائه می دهد. علاوه بر این فریم ورک Angular از کتابخانه RxJS استفاده می کند، که بر اساس برنامه نویسی reactive است و فرم های Reactive از این شیوه استفاده می کند.
چگونه :
import { Component } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @Component({ selector: 'app-registration', template: ` <form [formGroup]="registrationForm" (ngSubmit)="onSubmit()"> <input formControlName="username" placeholder="Username" /> <button type="submit" [disabled]="registrationForm.invalid">Register</button> </form> `, }) export class RegistrationComponent { registrationForm: FormGroup; constructor(private fb: FormBuilder) { this.registrationForm = this.fb.group({ username: ['', [Validators.required, Validators.minLength(5)]], }); } onSubmit() { // Manage submission here } }
چه : lazy load را برای ماژول های feature فعال کنید تا آنها را در زمان نیاز بارگیری کنید.
چرا : lazy load حجم اولیه بسته برنامه را کاهش می دهد و سرعت بارگذاری اولیه برنامه را افزایش می دهد. این ماژولارسازی عملکرد را بهبود میبخشد.
چگونه :
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; const routes: Routes = [ { path: 'dashboard', loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule), }, // Other routes... ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], }) export class AppRoutingModule { }
چه : یک تابع برای trackBy در حلقه های ngFor بنویسید.
چرا : عملکرد رندرینگ را برای لیست ها بهینه می کند.
چگونه :
// In component trackByFn(index: number, item: any): number { return item.id; } <!-- In template --> <div *ngFor="let item of items; trackBy: trackByFn">{{ item.name }}</div>
چه چیزی : کامنت های معنی دار اضافه کنید و کد خود را مستند کنید.
چرا : خوانایی کد را بهبود می بخشد و به توسعه دهندگان دیگر کمک می کند تا کد شما را درک کنند.
چگونه :
/** * This is an sample function that print a message in console and return length of input parameter. * @param {string} param - Description of the parameter. * @returns {number} Description of the return value. */ function helloFunction(name: string): number { // Function logic here console.log(`Hello ${name} length: ${name.length}`); return name.length; }
به علاوه : به منظور تولید مستندات پروژه Angular خود می توانید از این ابزار Compodoc استفاده کنید.
چه : از async pipe برای subscribe کردن به observableهای موجود در templatesها استفاده کنید.
چرا : subscriptionها را به صورت خودکار مدیریت می کند و با از بین رفتن کامپوننت اتصال را از بین میبرد و از نشت حافظه(memory leak) جلوگیری می کند.
چگونه :
// In component data$: Observable<Data>;
<!-- In template --> <div *ngIf="data$ | async as data">{{ data }}</div>
چه چیزی : برای استانداردهای کدنویسی ، به راهنمای رسمی Angular style پایبند باشید.
چرا : سازگاری خوانایی و قابلیت نگهداری را بهبود می بخشد.
چگونه :
// Bad function myComponent() {} // Good export class MyComponent {}
چه : business logic را در سرویس های Angular قرار دهید، نه کامپوننت ها.
چرا : جداسازی بخش ها و قابلیت استفاده مجدد از منطق.
چگونه :
@Injectable({ providedIn: 'root', }) export class MyService { getData(): Observable<Data> { // Write Service logic (business logic) here } }
@Component({ selector: 'app-my-component', templateUrl: 'my-component.component.html', }) export class MyComponent { currentValue: Data; constructor(private myService: MyService) { myService.getData().subscribe(v => { this.currentValue = v; }); } }
چه : انگولار lifecycle hook را برای مدیریت رفتار کامپوننت ها در لحظات کلیدی فراهم می کند. از متد هایی مانند ngOnInit
، ngOnChanges
و ngOnDestroy
و غیره به درستی استفاده کنید.
چرا : استفاده صحیح از متدهای initialization ، lifecycle hook کارآمد کامپوننت ها، اجرای بهتر change detection و پاکسازی بهتر کامپوننت ها را تضمین می کند.
چگونه :
import { Component, OnInit, OnDestroy } from '@angular/core'; @Component({ selector: 'app-example', template: '...', }) export class ExampleComponent implements OnInit, OnDestroy { constructor(){} ngOnInit() { // Initialization logic here } ngOnDestroy() { // Cleanup logic here } }
چه : از memory leak با unsubscribe کردن observableها در هنگام از بین رفتن کامپوننت ها جلوگیری کنید.
چرا : با unsubscribe کردن هنگام تخریب کامپوننت ها از subscribeهای طولانی مدت و بی استفاده جلوگیری می کنید، که می تواند منجر به نشت حافظه و رفتار غیرمنتظره شود.
چگونه :
import { Component, OnDestroy } from '@angular/core'; import { Subscription } from 'rxjs'; @Component({ selector: 'app-example', template: '...', }) export class ExampleComponent implements OnInit, OnDestroy { private subscription: Subscription; constructor(private dataService: DataService) { } ngOnInit() { this.subscription = this.dataService.getData().subscribe(data => { // Handle data }); } ngOnDestroy() { this.subscription.unsubscribe(); } }
چه : از interface ها برای تعریف نوع اشیا به جای استفاده از نوع "any" استفاده کنید.
چرا : interface ها ایمنی نوع داده ها و خوانایی بهتر کد را فراهم می کنند. هنگام نوشتن با IDE ترجیحی خود (VSCode، IntelliJ Idea یا موارد دیگر)، در طول توسعه راهنمایی می شویم. علاوه بر این ما از Angular استفاده می کنیم که بر اساس Typescript است که از برنامه نویسی شی گرا پشتیبانی می کند. OOP راهی برای سازماندهی کد و ایجاد برنامه های نرم افزاری قابل استفاده مجدد و ماژولار ارائه می دهد. برای انجام این کار، وراثت، encapsulation و polymorphism وجود دارند، اما اول از همه ما انواع داده ها را داریم. پس چرا به جای استفاده از "any" به درستی از آنها استفاده نمی کنیم؟
چگونه :
interface User { id: number; name: string; } function getUserInfo(user: User): string { // Access user properties safely return user.name + " (" + user.id + ")" }
چه چیزی : یک استایل کدنویسی ثابت را دنبال کنید و به راهنمای استایل Angular پایبند باشید.
چرا : کد یکنواخت خوانایی و همکاری بین توسعه دهندگان را افزایش می دهد.
چگونه :
چه : تست های واحد را با استفاده از ابزارهایی مانند Jasmine و Karma بنویسید. با استفاده از یک ابزار خاص برای e2e مانند Cypress، تست end-to-end انجام دهید.
چرا : تست قابلیت اطمینان کد را تضمین می کند، اشکالات را زودتر تشخیص می دهد و تغییرات کدهای آینده را تسهیل می کند.
چگونه (Unit test):
// example.component.spec.ts// example.e2e-spec.ts describe('Example App', () => { it('should display welcome message', () => { cy.visit('/'); cy.get('app-root').contains('Welcome to your Angular App!'); }); }); describe('ExampleComponent', () => { it('should create', () => { const component = new ExampleComponent(); expect(component).toBeTruthy(); }); });
چگونه (تست e2e):
// example.e2e-spec.ts describe('Example App', () => { it('should display welcome message', () => { cy.visit('/'); cy.get('app-root').contains('Welcome to your Angular App!'); }); });
چه : عملگرهای RxJS مانند map
, filter
, و mergeMap
تبدیل و دستکاری observable را به طور موثر انجام می دهند.
چرا : عملگرها عملیات پیچیده async را ساده می کنند و کد را مختصر و خوانا می کنند.
چگونه :
import { from } from 'rxjs'; import { map, filter } from 'rxjs/operators'; const numbers = from([1, 2, 3, 4, 5]); numbers.pipe( filter(num => num % 2 === 0), // Filters even numbers map(num => num * 2) // Doubles the filtered numbers ).subscribe(result => { console.log(result); // Output: 4, 8 });
import { Observable } from 'rxjs'; import { map, filter } from 'rxjs/operators'; // Example using map and filter operators observable.pipe( filter(data => data !== null), // Filter out null values map(data => data.property), // Extract a specific property ).subscribe(transformedData => { // Process transformed data });
چه : از subscribe کردن درون یک subscribe دیگر برای جلوگیری از callback hell و بهبود خوانایی کد خودداری کنید.
چرا : subscribeهای تودرتو میتوانند به کدهایی منجر شوند که نگهداری آن دشوار است، که به عنوان pyramid of doom «هرم عذاب» شناخته میشود. همچنین در صورت عدم مدیریت صحیح می تواند باعث نشت حافظه شود.
چگونه :
import { Observable } from 'rxjs'; import { switchMap } from 'rxjs/operators'; // Bad Practice (Nested Subscriptions) observable1.subscribe(data1 => { observable2.subscribe(data2 => { // Process data }); }); // Good Practice (Using switchMap) observable1.pipe( switchMap(data1 => { return observable2; }) ).subscribe(data2 => { // Process data });
چه : کامپوننت های قابل استفاده مجدد را برای کپسوله کردن عملکردها و توابع خاص و عناصر UI مربوط به آنها ایجاد کنید.
چرا : استفاده مجدد از کامپوننت ها قابلیت نگهداری را افزایش می دهد، تکرار را کاهش می دهد و ثبات کلی برنامه را افزایش می دهد.
چگونه :
// Reusable Component (Example) @Component({ selector: 'app-custom-button', template: '<button>{{label}}</button>' }) export class CustomButtonComponent { @Input() label: string; // Component logic and methods } // Implementation in Parent Component <app-custom-button [label]="'Click me'"></app-custom-button>
چه : از عملگرهای mapping مرتبه بالاتر مانند mergeMap
، concatMap
یا exhaustMap
بر اساس نیاز استفاده کنید.
چرا : عملگرهای mapping درجه بالاتر به شما امکان می دهند همزمانی را مدیریت کنید و انتشار observable را به شیوه ای کنترل شده مدیریت کنید و از مسائلی مانند race جلوگیری کنید.
چگونه :
import { Observable, from } from 'rxjs'; import { mergeMap } from 'rxjs/operators'; // Using mergeMap to handle concurrent requests observable.pipe( mergeMap(data => { return from(someAsyncOperation(data)); }) ).subscribe(result => { // Process the merged result });
در صورت امکان از پایپ async استفاده کنید (این توسط Angular پیشنهاد شده است). هنگامی که نمی توانید از async pipe استفاده کنید، از عملگرtakeUntil
به همراه Subject
برایunsubscribe دستی از observableها استفاده کنید.
عملگر takeUntil
به شما این امکان را می دهد تا در صورت وقوع یک رویداد خاص (که توسط Subject کنترل می شود) از observableها unsubscribe کنید و از نشت حافظه جلوگیری کنید.
چگونه :
import { Component, OnDestroy } from '@angular/core'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-example', template: 'Example Component' }) export class ExampleComponent implements OnDestroy { private unsubscribe$: Subject<void> = new Subject<void>(); constructor(private dataService: DataService) { this.dataService.getData() .pipe(takeUntil(this.unsubscribe$)) .subscribe(data => { // Handle data }); } ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } }
با پیروی از این best practiceها ، توسعهدهندگان Angular میتوانند کدی کارآمدتر، با خوانایی و قابلیت نگهداری بیشتر را ایجاد کنند و در عین حال از ویژگیهای قدرتمند ارائهشده توسطAngular و RxJS بهرهمند شوند .
این مقاله برگردان شده یک مقاله معتبر درباره این موضوع است.برای دسترسی به مقاله منبع اینجا کلیک کنید.
برای مشاهده پست های بیشتر و ارتباط با من از طریق لینکدین اینجا کلیک کنید.
امیدوارم براتون مفید واقع شده باشه.