角度性能调整综合指南
#javascript #网络开发人员 #angular #guide

看到角应用随着时间的流逝而放慢速度并不少见。 Angular是一个性能平台,但是如果我们不知道如何创建性能的角度应用,随着它们的发展,我们的应用程序将变得越来越慢。结果,任何严重的角开发人员都必须意识到是什么使角度应用程序慢一点,以防止其速度缓慢。

改善变更检测

更改检测可能是Angular应用程序中性能最密集的一部分,因此重要的是要了解如何有效地渲染模板,以便我们只需显示新的更改即可显示。

Onpush更改检测

当应用程序中发生异步事件时,例如单击,XMLHTTPRequest或Settimeout时,组件的默认更改检测行为将重新渲染。这可能是一个令人担忧的问题,因为它将导致许多尚未更新的模型的渲染。

  • 已向其输入属性之一添加了一个新的参考
  • 一个源自组件或其一个孩子的事件,例如单击组件按钮。
  • 显式移动检测运行
  • 要使用此技术,只需在组件的装饰器中设置变更检测策略,如下所示:
  @Component({
    selector: 'app-todo-list',
    templateUrl: './todo-list.component.html',
    styleUrls: ['./todo-list.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush
  })
  export class TodoListComponent implements OnInit {}

设计的不变性

由于我们需要对组件输入的新引用来用Onpush激活变更检测,因此我们必须确保所有状态更改都不可变化以使用此过程。如果我们使用Redux进行状态管理,我们会注意到每次状态更改时,我们都会获得一个新实例,这将在给出组件输入时会导致ONPUSH组件的更改检测。使用此方法,我们将需要容器组件来从商店获取数据,以及只能通过输入和输出与其他组件进行通信的演示组件。

异步管是向模板提供存储数据的最简单方法。这似乎将具有可观察到的数据之外的数据,并确保在对象自动破坏时清理流。

    <xml><div class="mx-auto col-10"><h5>{{'todo-list' | translate}}</h5>
<hr><app-cards-list></app-cards-list></div>
<hr><app-add-todo></app-add-todo>
    </xml>

使Onpush默认更改检测策略

在使用Angular CLI创建新组件时,我们可以使用原理图来渲染Onpush默认更改策略。在Angular中,只需将其添加到原理图的属性中即可。 JSON是一种数据。

  "schematics": {
    "@schematics/angular:component": {
      "styleext": "scss",
      "changeDetection": "OnPush"
    }
  }

在模板中使用管道代替方法

重新渲染组件时,将命名原型中的方法。即使使用OnPush更改检测,这意味着任何与组件或任何孩子相互作用(单击,键入)时,它也会被激活。如果方法执行密集的计算,则该应用程序会随着尺度的扩展而变得迟钝,因为它必须每次访问该零件时重新计算。

阅读更多:Accessibility With Angular

相反,我们可能会使用纯管道来确保当管道的输入移动时我们只是在重新计算。正如我们之前讨论的那样,异步管是纯管道的一个例子。当可观察到的散发值时,它将重新计算。如果我们要处理纯函数,我们希望确保我们只是在输入更改时重新计算。纯函数是给定相同输入的一个始终返回相同结果的功能。结果,如果输入没有更改,则重新计算输出是毫无意义的。

public getDuedateTodayCount(todoItems: TODOItem[]) {
console.log('Called getDuedateTodayCount');
return todoItems.filter((todo) => this.isToday(new Date(todo.dueDate))).length;
}
 private isToday(someDate) {
const today = new Date();
return (
someDate.getDate() == today.getDate() &&
someDate.getMonth() == today.getMonth() &&
someDate.getFullYear() == today.getFullYear()
);
}

使用方法

让我们看一下使用模板系统而不是管道时发生的事情。

考虑以下过程:

  public getDuedateTodayCount(todoItems: TODOItem[]) {
    console.log('Called getDuedateTodayCount');
    return todoItems.filter((todo) => this.isToday(new Date(todo.dueDate))).length;
  }
  private isToday(someDate) {
    const today = new Date();
    return (
      someDate.getDate() == today.getDate() &&
      someDate.getMonth() == today.getMonth() &&
      someDate.getFullYear() == today.getFullYear()
    );
  }

用管道

这可以通过将方法更改为管道来解决,该管道默认情况下是纯粹的,如果输入更改,则将重新运行逻辑。

我们通过构建新管道并转移以前使用的逻辑来获得以下结果:

    import { Pipe, PipeTransform } from '@angular/core';
    import { TODOItem } from '@app/shared/models/todo-item';
    @Pipe({
      name: 'duedateTodayCount'
    })
    export class DuedateTodayCountPipe implements PipeTransform {
      transform(todoItems: TODOItem[], args?: any): any {
        console.log('Called getDuedateTodayCount');
        return todoItems.filter((todo) => this.isToday(new Date(todo.dueDate))).length;
      }
      private isToday(someDate) {
        const today = new Date();
        return (
          someDate.getDate() == today.getDate() &&
          someDate.getMonth() == today.getMonth() &&
          someDate.getFullYear() == today.getFullYear()
        );
      }

纯管道和功能的缓存值

我们还可以通过记住/缓存以前的值来使用纯管道来提高此功能,这样我们就不必重新计算管道是否已经使用相同的输入运行。纯管道不会跟踪以前的值;取而代之的是,他们检查输入是否没有改变关系,以便不必重新计算。要执行以前的值缓存,我们需要将其与其他内容相结合。

lodash记忆方法是实现这一目标的简单方法。由于输入是一系列对象,因此在这种情况下这不是很现实。如果管道接受简单的数据类型作为输入,例如数字,则将其用作缓存结果并防止重新计算的关键可能是有利的。

在NGFOR中使用Trackby

在使用NGFOR更新列表时,Angular可以从DOM删除整个列表并重建整个列表,因为它无法验证已添加或删除哪个对象。 Trackby函数通过允许我们给Angular A函数来评估NGFOR列表中的哪个项目已修改或删除,然后重新渲染它来解决此问题。

c c c c c.

  public trackByFn(index, item) {
    return item.id;
  }

对于重型计算:分离变更检测

在极端情况下,我们只需要手动启用一些组件的更改检测即可。也就是说,如果一个组件是在同一页面上实例化的100次并重新渲染每个次数的成本,我们可以完全禁用组件的自动更改检测,并且仅在需要的情况下手动导致更改。

>

我们可以分离更改检测,并且只有在待办事项设置属性中设置to to tos属性时才运行此操作,如果我们选择为todo项目执行此操作:

  @Component({
    selector: 'app-todo-item-list-row',
    templateUrl: './todo-item-list-row.component.html',
    styleUrls: ['./todo-item-list-row.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush
  })
  export class TodoItemListRowComponent implements OnInit {
    private _todoItem : TODOItem;
    public get todoItem() : TODOItem {
      return this._todoItem;
    }
    @Input()
    public set todoItem(v : TODOItem) {
      this._todoItem = v;
      this.cdr.detectChanges();
    }  
    @Input() public readOnlyTODO: boolean;
    @Output() public todoDelete = new EventEmitter();
    @Output() public todoEdit = new EventEmitter();
    @Output() public todoComplete = new EventEmitter<todoitem>();

    constructor(private cdr: ChangeDetectorRef) {}
    public ngOnInit() {
      this.cdr.detach();
    }
    public completeClick() {
      const newTodo = {
        ...this.todoItem,
        completed: !this.todoItem.completed
      };
      this.todoComplete.emit(newTodo);
    }
    public deleteClick() {
      this.todoDelete.emit(this.todoItem.id);
    }
    public editClick() {
      this.todoEdit.emit(this.todoItem);
    }
  }
</todoitem>

改进页面负载

网站加载所需的时间是当今用户体验的重要因素。用户等待的每毫秒都会由于跳出率更高和用户体验差而导致销售损失,因此这是我们应该集中精力的领域。搜索引擎会奖励更快的网站,因此页面加载时间对SEO有影响。

我们想使用Angular PWA缓存,懒惰加载和捆绑来改善页面加载时间。

使用Angular PWA缓存静态内容

由于静态内容已经在浏览器中,因此缓存将使我们的Angular App负载更快。这很容易使用Angular PWA完成,该Angular PWA使用服务工作者存储和呈现静态内容,例如JavaScript,CSS捆绑包,图像和静态服务文件,而无需服务器请求。

寻找真正的Angular Development Company?今天询问。

使用Angular PWA的缓存HTTP调用

我们可以轻松地使用Angular PWA设置HTTP调用的缓存规则,以使我们的应用程序更快地使用用户体验,而无需使用很多缓存代码。我们可以优化新鲜度或效率,也就是说,仅在HTTP呼叫时间输出时才读取缓存,或者先检查缓存,然后仅在缓存到期时拨打API。

懒负载路由

懒惰的加载路线确保每个功能都包装在自己的捆绑包中,并且只有在需要时才能加载此捆绑包。

要允许懒惰加载,只需在这样的函数中构建子路由文件:

  const routes: Routes = [
  {
    path: '',
    component: TodoListCompletedComponent
  }
];
export const TodoListCompletedRoutes = RouterModule.forChild(routes);

导入路由:

  @NgModule({
    imports: [FormsModule, CommonModule, SharedModule, TodoListCompletedRoutes],
    declarations: [TodoListCompletedComponent]
  })
  export class TodoListCompletedModule {}

在根路由中使用LoadChildren:

  const appRoutes: Routes = [
  {
    path: rootPath,
    component: TodoListComponent,
    pathMatch: 'full'
  },
  {
    path: completedTodoPath,
    loadChildren: './todo-list-completed/todo-list-completed.module#TodoListCompletedModule'
  }
];
export const appRouterModule = RouterModule.forRoot(appRoutes);

优化捆绑和预加载

我们可能会选择预订功能模块以进一步加快页面加载。这样,当我们选择制作懒惰的功能模块时,导航即将立即。

这可以通过将预载体模块设置为前层膜片来实现:

RouterModule.forRoot(routes, {
preloadingStrategy: PreloadAllModules
 })

页面加载时,将加载所有功能模块,当我们选择加载其他功能模块时,可以更快地加载页面加载和即时导航。可以通过使用自定义预加载策略(如此处显示的一种仅加载应用程序启动上的路由的子集)来进一步优化。

用角通用的服务器端渲染

建议将服务器端渲染用于包含索引页面的角应用。这样可以确保页面完全由服务器制作,然后再显示浏览器,从而导致页面加载更快。这将需要该应用不依赖任何本机DOM组件,而是从Angular提供商处注入文档。

改善UX

性能调整就是要改善瓶颈,这是系统的一部分,对用户体验产生了最大的影响。通常,替代方案只是更乐观地对待行为,从而减少了对客户的等待。

乐观的更新

在保存在服务器上之前在用户界面中表达更改时,会发生乐观的更改。因此,用户将具有类似于本机的敏捷经验。结果,如果服务器无法保存更改,我们必须退缩状态。 Strongbrew写了一篇有关如何以通用方式执行此操作的文章,使积极的更改简单地在我们的代码中实施。

我们应该如何优先考虑性能调整?

从低悬挂的水果开始:Onpush,懒惰的加载和PWA,然后弄清楚系统的输出瓶颈在哪里。任何无法解决瓶颈的增强功能都是海市rage楼,因为它不会增强应用程序的用户体验。分离变更检测是一种调谐技术,仅当我们遇到特定问题的情况下,该技术会影响输出。

结论

在此博客中,我们学会了如何在本文中调整Angular应用的输出。更改检测,页面负载和UX增强功能是我们查看的一些性能调整类别。系统中的任何更改均应从识别瓶颈开始,并尝试使用本文中描述的一种方法来解决它们。