Рубрики
Без рубрики

Лучшие практики для чистого и исполнительного углового приложения

Передовые практики Vamsi Vempati для чистых и исполнительных угловых Applicationi работают над крупным угловым приложением в отношении меня, новой Зеландии на пару лет. За последние несколько лет наша команда уточняет наше применение как с точки зрения стандартов кодирования

Автор оригинала: FreeCodeCamp Community Member.

Vamsi Vempati

Я работаю над большим угловым приложением на Торговля мне Новая Зеландия на пару лет сейчас. За последние несколько лет наша команда уточняет нашу заявку как с точки зрения стандартов и производительности кодирования, чтобы она была в лучшем состоянии.

В этой статье описываются практики, которые мы используем в нашем приложении и связаны с угловым, типографическим, RXJS и @ Ngrx/Store. Мы также пройдем некоторые общие руководящие принципы кодирования, чтобы помочь сделать очиститель приложений.

1) TrackBy.

При использовании NGFOR Чтобы петить на массиве в шаблонах, используйте его с Trackby Функция, которая вернет уникальный идентификатор для каждого элемента.

Почему?

Когда массив меняется, угловые повторные ретримоты все дерево DOM. Но если вы используете Trackby , Угловые знают, какой элемент изменился, и сделает только изменения DOM для этого конкретного элемента.

Для подробного объяснения этого объяснения, пожалуйста, обратитесь к Эта статья По Нетанель Базал Отказ

Перед

  • {{ item }}
  • После

    // in the template
    
    
  • {{ item }}
  • // in the component trackByFn(index, item) { return item.id; // unique id corresponding to the item }

    2) const vs пусть

    При объявлении переменных используйте Const, когда значение не будет переназначено.

    Почему?

    Использование Пусть и Const где целесообразно делает намерение заявлений яснее. Это также поможет в выявлении проблем, когда значение переназначается постоянно случайно, выбрасывая ошибку времени компиляции. Это также помогает улучшить читаемость кода.

    Перед

    let car = 'ludicrous car';
    
    let myCar = `My ${car}`;
    let yourCar = `Your ${car};
    
    if (iHaveMoreThanOneCar) {
       myCar = `${myCar}s`;
    }
    
    if (youHaveMoreThanOneCar) {
       yourCar = `${youCar}s`;
    }

    После

    // the value of car is not reassigned, so we can make it a const
    const car = 'ludicrous car';
    
    let myCar = `My ${car}`;
    let yourCar = `Your ${car};
    
    if (iHaveMoreThanOneCar) {
       myCar = `${myCar}s`;
    }
    
    if (youHaveMoreThanOneCar) {
       yourCar = `${youCar}s`;
    }

    3) непродовольственные операторы

    Используйте трубопроводные операторы при использовании операторов RXJS.

    Почему?

    Непрецесканные операторы – это дробильное дерево, означающее только код, который нам нужен для выполнения, будет включен, когда они импортируются.

    Это также позволяет легко идентифицировать неиспользованные операторы в файлах.

    Примечание: Это нуждается в угловой версии 5.5+.

    Перед

    import 'rxjs/add/operator/map';
    import 'rxjs/add/operator/take';
    
    iAmAnObservable
        .map(value => value.item)
        .take(1);

    После

    import { map, take } from 'rxjs/operators';
    
    iAmAnObservable
        .pipe(
           map(value => value.item),
           take(1)
         );

    4) Изолировать API Hacks

    Не все API – это доказательство пули – иногда нам нужно добавить некоторую логику в коде для компенсации ошибок в API. Вместо того, чтобы взломать в компонентах, где они нужны, лучше изолировать их в одном месте – как в сервисе и использовать сервис от компонента.

    Почему?

    Это помогает сохранить хаки «ближе к API», так как близок, где создан сетевой запрос. Таким образом, меньше вашего кода имеет дело с взломанным кодом. Кроме того, это одно место, где живут все хаки, и их легче найти. При исправлении ошибок в API проще искать их в одном файле, а не в поисках хаки, которые могут быть распространены по кодовой базе.

    Вы также можете создавать пользовательские метки, такие как API_FIX, похожие на TODO и течь исправлениями, так что легче найти.

    5) Подписаться в шаблоне

    Избегайте подписки к наблюдаемым от компонентов и вместо этого подписаться на наблюдаемые за шаблон.

    Почему?

    async Трубы отказались отписаться автоматически, и делает код проще, устраняя необходимость вручную управлять подпискими. Это также снижает риск случайно забыть от подписки подписки в компоненте, что приведет к утечке памяти. Этот риск также может быть смягчен, используя правило Lint для обнаружения отписавшихся наблюдаемых наблюдателей.

    Это также останавливает компоненты изготовления состояния и внедрения ошибок, где данные могут мутировать за пределами подписки.

    Перед

    // // template
    
    

    {{ textToDisplay }}

    // component iAmAnObservable .pipe( map(value => value.item), takeUntil(this._destroyed$) ) .subscribe(item => this.textToDisplay = item);

    После

    // template
    
    

    {{ textToDisplay$ | async }}

    // component this.textToDisplay$ = iAmAnObservable .pipe( map(value => value.item) );

    6) Очистить подписки

    Когда подписывается на наблюдаемые, всегда убедитесь, что вы не подпишитесь от них соответствующим образом с помощью операторов, таких как Возьми , доставка , так далее.

    Почему?

    Неспособность отписаться от наблюдаемых, приведет к нежелательной утечке памяти, поскольку наблюдаемый поток оставлен открытым, потенциально даже после уничтожения компонента/пользователь навигации к другой странице.

    Даже лучше, сделайте правило века для обнаружения наблюдаемых, которые не отказываются.

    Перед

    iAmAnObservable
        .pipe(
           map(value => value.item)     
         )
        .subscribe(item => this.textToDisplay = item);

    После

    Использование доставка Когда вы хотите прослушать изменения, пока другой не наблюдаемый не испускает значение:

    private _destroyed$ = new Subject();
    
    public ngOnInit (): void {
        iAmAnObservable
        .pipe(
           map(value => value.item)
          // We want to listen to iAmAnObservable until the component is destroyed,
           takeUntil(this._destroyed$)
         )
        .subscribe(item => this.textToDisplay = item);
    }
    
    public ngOnDestroy (): void {
        this._destroyed$.next();
        this._destroyed$.complete();
    }

    Использование частной темы, как это, это шаблон для управления отписавшимися многими наблюдателями в компоненте.

    Использование Возьми Когда вы хотите только первое значение, испускаемое наблюдаемым:

    iAmAnObservable
        .pipe(
           map(value => value.item),
           take(1),
           takeUntil(this._destroyed$)
        )
        .subscribe(item => this.textToDisplay = item);

    Обратите внимание на использование доставка с Возьми здесь. Это следует избегать утечек памяти, вызванные, когда подписка не получила значение до того, как компонент не будет уничтожен. Без доставка Здесь подписка все равно повесится, пока не получит первое значение, но поскольку компонент уже получил уничтожение, он никогда не получит значение – ведущий к утечке памяти.

    7) Используйте соответствующие операторы

    При использовании выравнивания операторов с вашими наблюдателями используйте соответствующий оператор для ситуации.

    Переключатель: Когда вы хотите игнорировать предыдущие выбросы, когда есть новый выброс

    Mergemap: Когда вы хотите одновременно обрабатывать все выбросы

    CONCATMAP: Когда вы хотите обрабатывать выбросы один за другим, поскольку они издаются

    Выпускной удар: Когда вы хотите отменить все новые выбросы при обработке предыдущего выброса

    Для более подробного объяснения этого объясните, пожалуйста, обратитесь к это Статья по Николас Джеймисон Отказ

    Почему?

    Используя единственный оператор, когда это возможно, вместо цепочки вместе с несколькими другими операторами для достижения того же эффекта может привести к тому же коду для отправки пользователю. Использование неправильных операторов может привести к нежелательному поведению, так как разные операторы обрабатывают наблюдаемые по-разному.

    8) ленивая нагрузка

    Когда это возможно, попробуйте лениться нагружать модули в угловой приложение. Ленивая нагрузка – это когда вы загружаете что-то только тогда, когда он используется, например, загрузка компонента только тогда, когда его можно увидеть.

    Почему?

    Это уменьшит размер приложения, который будет загружен и может улучшить время загрузки приложения, не загружая модули, которые не используются.

    Перед

    // app.routing.ts
    
    { path: 'not-lazy-loaded', component: NotLazyLoadedComponent }

    После

    // 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 {}

    9) Избегайте имении подписок внутри подписок

    Иногда вы можете захотеть значения более одного наблюдаемого для выполнения действия. В этом случае избегайте подписки на один наблюдаемый в блоке подписки другого наблюдаемого. Вместо этого используйте соответствующие операторы цепочки. Операторы цепочки бегут наблюдате на наблюдаемые от оператора перед ними. Некоторые операторы цепочки: уллатест от , комбинация , так далее.

    Перед

    firstObservable$.pipe(
       take(1)
    )
    .subscribe(firstValue => {
        secondObservable$.pipe(
            take(1)
        )
        .subscribe(secondValue => {
            console.log(`Combined values are: ${firstValue} & ${secondValue}`);
        });
    });

    После

    firstObservable$.pipe(
        withLatestFrom(secondObservable$),
        first()
    )
    .subscribe(([firstValue, secondValue]) => {
        console.log(`Combined values are: ${firstValue} & ${secondValue}`);
    });

    Почему?

    Кодовый запах/читабельность/сложность : Не используя RXJS в полной мере, предлагает разработчик не знаком с площадью поверхности API RXJS.

    Производительность : Если наблюдаемые стойки холодные, он будет подписаться на FirstoBSeribable, ждать его завершения, а затем начать работу второго наблюдаемого. Если это были сетевые запросы, это будет отображаться как синхронный/водопад.

    10) избегать любого; Введите все;

    Всегда объявляйте переменные или константы с типом, кроме любой Отказ

    Почему?

    При объявлении переменных или констант в TypeScript без печати, набрав переменной/константу будет выводится по значению, которое присваивается ему. Это приведет к непреднамеренным проблемам. Один классический пример:

    const x = 1;
    const y = 'a';
    const z = x + y;
    
    console.log(`Value of z is: ${z}`
    
    // Output
    Value of z is 1a

    Это может вызвать нежелательные проблемы, когда вы ожидаете, что у вас тоже будет число. Эти проблемы можно избежать, набрав переменные соответствующим образом.

    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

    Таким образом, мы можем избежать ошибок, вызванных недостающимися типами.

    Еще одним преимуществом хороших наведений в вашем приложении является то, что он облегчает рефакторинг и безопаснее.

    Рассмотрим этот пример:

    public ngOnInit (): void {
        let myFlashObject = {
            name: 'My cool name',
            age: 'My cool age',
            loc: 'My cool location'
        }
        this.processObject(myFlashObject);
    }
    
    public processObject(myObject: any): void {
        console.log(`Name: ${myObject.name}`);
        console.log(`Age: ${myObject.age}`);
        console.log(`Location: ${myObject.loc}`);
    }
    
    // Output
    Name: My cool name
    Age: My cool age
    Location: My cool location

    Покажем, мы хотим переименовать свойство loc к Расположение в MyFlaShobject :

    public ngOnInit (): void {
        let myFlashObject = {
            name: 'My cool name',
            age: 'My cool age',
            location: 'My cool location'
        }
        this.processObject(myFlashObject);
    }
    
    public processObject(myObject: any): void {
        console.log(`Name: ${myObject.name}`);
        console.log(`Age: ${myObject.age}`);
        console.log(`Location: ${myObject.loc}`);
    }
    
    // Output
    Name: My cool name
    Age: My cool age
    Location: undefined

    Если у нас нет печатания на MyFlaShobject думает, что отель loc на MyFlaShobject просто неопределен, а не то, что это не допустимое свойство.

    Если бы у нас было набрать для MyFlaShobject , мы получим приятную ошибку времени компиляции, как показано ниже:

    type FlashObject = {
        name: string,
        age: string,
        location: string
    }
    
    public ngOnInit (): void {
        let myFlashObject: FlashObject = {
            name: 'My cool name',
            age: 'My cool age',
            // Compilation error
            Type '{ name: string; age: string; loc: string; }' is not assignable to type 'FlashObjectType'.
            Object literal may only specify known properties, and 'loc' does not exist in type 'FlashObjectType'.
            loc: 'My cool location'
        }
        this.processObject(myFlashObject);
    }
    
    public processObject(myObject: FlashObject): void {
        console.log(`Name: ${myObject.name}`);
        console.log(`Age: ${myObject.age}`)
        // Compilation error
        Property 'loc' does not exist on type 'FlashObjectType'.
        console.log(`Location: ${myObject.loc}`);
    }

    Если вы начинаете новый проект, он стоит установить Строгий: правда В tsconfig.json Файл, чтобы включить все строгие параметры проверки типа.

    11) Воспользуйтесь правилами Lint

    Цлинт Различные варианты встроены уже вроде Нет-нибудь , No-Magic-Numbers , Нет консоли и т. Д., Что вы можете настроить в вашем Tslint.json Чтобы обеспечить определение определенных правил в вашей базе кода.

    Почему?

    Наличие правил Lint на месте означает, что вы получите хорошую ошибку, когда вы делаете то, что вы не должны быть. Это обеспечит согласованность в вашем приложении и читабельности. Пожалуйста, обратитесь здесь Для получения дополнительных правил, которые вы можете настроить.

    Некоторые правила Lint даже приходят с исправлениями для устранения ошибки Lint. Если вы хотите настроить собственное правило на заказ, вы можете сделать это тоже. Пожалуйста, обратитесь к Эта статья По Крейг Спенс О том, как написать свои собственные правила Custom Lint, используя Цури Отказ

    Перед

    public ngOnInit (): void {
        console.log('I am a naughty console log message');
        console.warn('I am a naughty console warning message');
        console.error('I am a naughty console error message');
    }
    
    // Output
    No errors, prints the below on console window:
    I am a naughty console message
    I am a naughty console warning message
    I am a naughty console error message

    После

    // tslint.json
    {
        "rules": {
            .......
            "no-console": [
                 true,
                 "log",    // no console.log allowed
                 "warn"    // no console.warn allowed
            ]
       }
    }
    
    // ..component.ts
    
    public ngOnInit (): void {
        console.log('I am a naughty console log message');
        console.warn('I am a naughty console warning message');
        console.error('I am a naughty console error message');
    }
    
    // Output
    Lint errors for console.log and console.warn statements and no error for console.error as it is not mentioned in the config
    
    Calls to 'console.log' are not allowed.
    Calls to 'console.warn' are not allowed.

    12) небольшие многоразовые компоненты

    Извлеките кусочки, которые можно повторно использовать в компоненте и сделать его новым. Составьте компонент максимально глупым, так как это сделает его работать в более сценариях. Создание компонента глупости означает, что компонент не имеет никакой специальной логики в нем и работает исключительно на основе входов и выходов, предоставленных ему.

    Как правило, последний ребенок в области компонентов будет самым глумным из всех.

    Почему?

    Многоразовые компоненты уменьшают дублирование кода, поэтому облегчают сохранение и внесение изменений.

    Тупые компоненты проще, поэтому они с меньшей вероятностью будут иметь ошибки. Тупые компоненты заставляют вас задуматься о API общедоступных компонентов и помогите понюхать смешанные проблемы.

    13) Компоненты должны иметь дело только с логикой дисплея

    Избегайте не имея никакой логики, кроме логики отображения в вашем компоненте всякий раз, когда вы можете сделать компонент только с логикой дисплея.

    Почему?

    Компоненты предназначены для презентационных целей и контроля, какой вид должен сделать. Любая деловая логика должна быть извлечена в свои собственные методы/услуги, где это уместно, разделение бизнес-логики от просмотра логики.

    Бизнес-логика, как правило, проще для удаления теста при извлечении к услуге и может быть повторно использовано любыми другими компонентами, которые нуждается в том же деловой логике.

    14) Избегайте длительных методов

    Длинные методы обычно указывают на то, что они делают слишком много вещей. Попробуйте использовать единственный принцип ответственности. Сам метод в целом может делать одно, но внутри него есть несколько других операций, которые могут произойти. Мы можем извлечь эти методы в свой собственный метод и заставить их делать одно и использовать их и использовать их вместо этого.

    Почему?

    Длинные методы трудно читать, понимать и поддерживать. Они также склонны к ошибкам, как изменение одной вещи может повлиять на множество других вещей в этом методе. Они также делают рефакторинг (что является ключевым вещью в любом приложении) сложно.

    Это иногда измеряется как « цикломатическая сложность ». Есть также некоторые Правила Цлинта Чтобы обнаружить цикломатическую/когнитивную сложность, которую вы можете использовать в вашем проекте, чтобы избежать ошибок и обнаруживать запах кода и вопросов ремонтопригодности.

    15) сухой

    Не повторяйся. Убедитесь, что у вас нет того же кода, скопированного в разные места в кодовой базе. Извлеките повторяющийся код и используйте его вместо повторного кода.

    Почему?

    Имея тот же код в нескольких местах означает, что если мы хотим внести изменения в логику в этом коде, мы должны сделать это в нескольких местах. Это затрудняет обслуживание, а также склонна к ошибкам, где мы могли бы пропустить обновление его во всех случаях. Требуется дольше, чтобы внести изменения в логику и тестирование, а также длительный процесс.

    В этих случаях извлеките повторяющийся код и используйте его вместо этого. Это означает только одно место для изменения и одну вещь для тестирования. Наличие менее дублированного кода, отправленного пользователями, означает, что приложение будет быстрее.

    16) Добавить механизмы кэширования

    При создании вызовов API ответы от некоторых из них не меняются часто. В этих случаях вы можете добавить механизм кэширования и хранить значение из API. Когда другой запрос к тому же API сделан, проверьте, есть ли значение для него в кэше, и если это так, используйте его. В противном случае сделайте вызов API и кэлит результатом.

    Если значения изменяются, но не часто, вы можете ввести время кэширования, где вы можете проверить, когда он был последним кэшированием и решить, следует ли вызвать ли API.

    Почему?

    Наличие механизма кэширования означает избегать нежелательных вызовов API. Только сделав вызовы API при необходимости и избегания дублирования, скорость приложения улучшается, поскольку нам не нужно ждать сети. Это также означает, что мы не загружаем ту же информацию снова и снова.

    17) Избегайте логики в шаблонах

    Если у вас есть какая-то логика в своих шаблонах, даже если это простой && Пункт, это хорошо извлечь его в его компонент.

    Почему?

    Имея логику в шаблоне означает, что невозможно установить его, и поэтому он более склонен к ошибкам при изменении шаблонного кода.

    Перед

    // template
    

    Status: Developer

    // component public ngOnInit (): void { this.role = 'developer'; }

    После

    // template
    

    Status: Developer

    // component public ngOnInit (): void { this.role = 'developer'; this.showDeveloperStatus = true; }

    18) Строки должны быть в безопасности

    Если у вас есть переменная строки типа, которая может иметь только набор значений, вместо того, чтобы объявлять его как тип строки, вы можете объявить список возможных значений в качестве типа.

    Почему?

    Объявив тип переменной соответствующим образом, мы можем избежать ошибок во время записи кода во время компиляции, а не во время выполнения.

    Перед

    private myStringValue: string;
    
    if (itShouldHaveFirstValue) {
       myStringValue = 'First';
    } else {
       myStringValue = 'Second'
    }

    После

    private myStringValue: 'First' | 'Second';
    
    if (itShouldHaveFirstValue) {
       myStringValue = 'First';
    } else {
       myStringValue = 'Other'
    }
    
    // This will give the below error
    Type '"Other"' is not assignable to type '"First" | "Second"'
    (property) AppComponent.myValue: "First" | "Second"

    Большая картина

    Государственное управление

    Рассмотрим использование @ Ngrx/Store Для поддержания состояния вашего приложения и @ Ngrx/Effects Как модель побочного эффекта для магазина. Изменения состояния описываются действиями, и изменения выполняются чистыми функциями, называемыми редукторами.

    Почему?

    @ Ngrx/Store Изолирует все состоятельные, связанные с логикой в одном месте и делает его в соответствии с приложением. Он также имеет механизм памяти на месте при доступе к информации в магазине, ведущем к более эффективному приложению. @ Ngrx/Store в сочетании с стратегией обнаружения изменения угловых приводит к более быстрому применению.

    Неизменное состояние

    При использовании @ Ngrx/Store Рассмотрите возможность использования Ngrx-Store-Freeze сделать состояние неизменной. Ngrx-Store-Freeze Предотвращает мутировать штату, бросая исключение. Это позволяет избежать случайной мутации государства, ведущего к нежелательным последствиям.

    Почему?

    Мутирование состояния в компонентах приводит к ведущему ведущему ведущему ведущему ведущению приложения в зависимости от компонентов заказа загружены. Это нарушает умственную модель рисунка Redux. Изменения могут в конечном итоге переопределить, если изменяет состояние хранилища и повторно выделяет. Разделение проблем – компоненты – это просмотр слоя, они не должны знать, как изменить состояние.

    Востребоваться

    Jest Является ли структура тестирования устройства Facebook для JavaScript. Это делает тестирование подразделения быстрее отпараллелизобравшегося теста на базе кода. Благодаря своему режиму наблюдения, только тесты, связанные с внесенными изменениями изменения, что делает цикл обратной связи для более короткой тестирования. Jest Также предоставляет кодовое покрытие тестов и поддерживается на VS Code и Webstorm.

    Вы могли бы использовать предустановка Для шума, что будет делать большую часть тяжелой подъема для вас, при настройке шума в вашем проекте.

    Карма

    Карма Это тестовый бегун, разработанный командой Angularjs. Для запуска тестов требуется настоящий браузер/DOM. Он также может работать на разных браузерах. Jest не нуждается в Chrome rudless/Phantomjs, чтобы запустить тесты, и он работает в чистом узле.

    Универсальный

    Если вы еще не сделали свое приложение A Универсальный Приложение, сейчас самое хорошее время, чтобы сделать это. Угловой универсальный Позволяет запустить ваше угловое приложение на сервере и набом бокового сервера (SSR), которые обслуживают статические предварительно отображаемые HTML-страницы. Это делает приложение Super Fast, так как он показывает контент на экране почти мгновенно, без необходимости ждать пакетов JS для загрузки и анализа или для углового уровня для загрузки.

    Это также удобно, так как угловая универсальная генерирует статический контент, и облегчает пропустить веб-скандиров для индексации приложения и сделать его поиском, не выполняющим JavaScript.

    Почему?

    Универсальный улучшает производительность вашего приложения резко. Недавно мы обновили наше приложение, чтобы сделать рендеринг боковых серверов, и время загрузки сайта вышло с нескольких секунд, чтобы десятки миллисекунд !!

    Это также позволяет вашему сайту правильно отображаться в Social Media Preview Snippets. Первая значимая краска действительно быстрая и делает контент видимым пользователям без каких-либо нежелательных задержек.

    Вывод

    Строительные приложения – это постоянное путешествие, и всегда есть место для улучшения вещей. Этот список оптимизации является хорошим местом для начала и применения этих шаблонов последовательно сделают вашу команду счастливой. Ваши пользователи также будут любить вас за хороший опыт работы с вашим менее баггическим и исполнителем.

    Спасибо за чтение! Если вам понравилось эту статью, пожалуйста, не стесняйтесь ? и помогите другим найти это. Пожалуйста, не стесняйтесь делиться своими мыслями в разделе комментариев ниже. Следуй за мной на Средний или Twitter Для получения дополнительных статей. Счастливые кодировки люди !! ? ☕️.