什么是 Angular 应用里的 MemorizedSelector

举报
汪子熙 发表于 2025/02/09 10:28:17 2025/02/09
117 0 0
【摘要】 在讨论 Angular 应用里的 MemoizedSelector 之前,需要对几个背景概念有一个清晰的理解,这包括什么是 Selector、Memoization(记忆化)、以及它们在 Angular 应用中的角色。 Selector 与 Memoization在 NgRx 架构中,Selector 是一种对 Store 中的状态进行查询的工具。它们允许你从全局状态中派生出所需的子状态。S...

在讨论 Angular 应用里的 MemoizedSelector 之前,需要对几个背景概念有一个清晰的理解,这包括什么是 Selector、Memoization(记忆化)、以及它们在 Angular 应用中的角色。

Selector 与 Memoization

在 NgRx 架构中,Selector 是一种对 Store 中的状态进行查询的工具。它们允许你从全局状态中派生出所需的子状态。Selector 不仅能简化状态的访问,还能提高代码的可维护性。

Memoization 是一种优化技术,它通过缓存函数的计算结果来避免重复计算。在调用有副作用或者计算开销大的函数时,Memoization 可以显著提升性能。

Memoized Selector 的概念

MemoizedSelector 简单来说,就是一个应用了 Memoization 技术的 Selector。它在同样的输入参数下,会返回缓存的结果,而不是重新计算。这种特性对提升性能,特别是在处理复杂和频繁状态选择操作时,尤其重要。

为什么需要 MemoizedSelector

在大多数实际应用中,状态查询不仅频繁,而且可能涉及复杂的计算。频繁的复杂计算会引发性能问题,导致应用变慢。MemoizedSelector 能够有效地解决这个问题,因为它们在同样的输入下返回缓存的结果,从而避免了重复计算。

创建 MemoizedSelector 的方法

在 NgRx 中,通过 createSelector 函数可以创建 MemoizedSelector。createSelector 函数接受一个或多个输入 Selectors 和一个项目函数,这个项目函数应用于输入 Selectors 的结果来产生新的值。

示例说明

为了直观地理解 MemoizedSelector 的使用,以下将展示一个具体的例子。

Step 1: 定义状态接口

假设我们有一个简单的应用状态接口,代表了一个用户和其任务列表。

interface UserState {
  currentUser: {
    id: number;
    name: string;
  };
  tasks: {
    id: number;
    title: string;
    completed: boolean;
  }[];
}

Step 2: 定义初始状态

初始状态的定义如下:

const initialState: UserState = {
  currentUser: {
    id: 1,
    name: 'Alice',
  },
  tasks: [
    { id: 1, title: 'Task 1', completed: false },
    { id: 2, title: 'Task 2', completed: true },
  ],
};

Step 3: 创建 Selectors

定义两个基础 Selectors:一个用来选择当前用户,另一个用来选择用户的任务列表。

import { createSelector, createFeatureSelector } from '@ngrx/store';

const selectUserState = createFeatureSelector<UserState>('user');

const selectCurrentUser = createSelector(
  selectUserState,
  (state: UserState) => state.currentUser
);

const selectUserTasks = createSelector(
  selectUserState,
  (state: UserState) => state.tasks
);

Step 4: 创建 MemoizedSelector

现在使用基础 Selectors 创建一个 MemoizedSelector,用来选择当前用户的未完成任务。

const selectPendingTasks = createSelector(
  selectUserTasks,
  (tasks) => tasks.filter(task => !task.completed)
);

上述 selectPendingTasks 是一个 MemoizedSelector,每当 selectUserTasks 的输出没有改变时,它将返回缓存的结果,避免重复计算。

MemoizedSelector 的优点

  1. 性能优化

    • MemoizedSelector 大大减少了复杂计算和状态选择的次数,如果状态没有变化,它们将总是返回缓存的结果。
  2. 更简洁的代码

    • 用 MemoizedSelector 来组合选择逻辑,能够将复杂的选择逻辑封装起来,这使得代码更简洁易读。
  3. 可重用性

    • 通过将选择逻辑封装在 Selectors 中,可以在不同的组件和服务之间重用它们,提升代码的可维护性和灵活性。

进一步优化

为了更深入了解 MemoizedSelector 的强大,还可以考虑一些高级用法。例如,对于需要根据多个状态计算结果的情况,可以进一步组合多个 MemoizedSelector。

const selectCompletedTasks = createSelector(
  selectUserTasks,
  (tasks) => tasks.filter(task => task.completed)
);

const selectTaskStats = createSelector(
  selectPendingTasks,
  selectCompletedTasks,
  (pendingTasks, completedTasks) => ({
    pendingCount: pendingTasks.length,
    completedCount: completedTasks.length
  })
);

具体应用情境

  1. 动态表单

    • 在处理复杂表单时,通过 MemoizedSelector,可以根据表单状态派生出一些辅助信息,如表单的有效性、错误提示等,用来提升用户体验。
  2. 分页和过滤

    • 当数据量较大时,可以通过 MemoizedSelector 对数据进行分页、排序和过滤,这样可以显著提升列表的渲染性能。
  3. 权限控制

    • 在应用中,根据用户权限动态显示或隐藏界面元素,可以通过 MemoizedSelector 根据用户状态派生出权限控制信息。

性能监控与调试

虽然 MemoizedSelector 可以显著提升性能,还是需要在实际应用中配合性能监控工具(如 @ngrx/store-devtools)来监控应用的性能瓶颈。同时,也可以通过撰写单元测试来确保 MemoizedSelector 的正确性。

import { TestBed } from '@angular/core/testing';
import { StoreModule, Store } from '@ngrx/store';
import { userReducer } from './user.reducer';
import { selectPendingTasks } from './user.selectors';

describe('User Selectors', () => {
  let store: Store<UserState>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        StoreModule.forRoot({ user: userReducer }),
      ],
    });

    store = TestBed.inject(Store);
  });

  it('should select pending tasks', () => {
    let result;

    store.select(selectPendingTasks).subscribe(value => {
      result = value;
    });

    store.dispatch({ type: '[User] Load Success', payload: initialState });

    expect(result).toEqual([
      { id: 1, title: 'Task 1', completed: false },
    ]);
  });
});

总结与展望

MemoizedSelector 在实际开发中是一个非常重要的工具,尤其在需要处理频繁的状态查询和复杂计算时,可以提供显著的性能提升。理解和熟练运用 MemoizedSelector,对于编写高效、可维护的 Angular 应用至关重要。未来,在 Angular 和 RxJS 生态系统中,不断优化和创新的选择器和状态管理技术,也必将进一步推动前端开发的高效性和用户体验的提升。

通过上面的详细讲解与代码示例,希望能帮助大家更好地理解 MemoizedSelector 的概念,以及如何在实际项目中运用这一技术来优化和改善应用性能。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。