在计算机编程畛域中,memoization 或 memoisation 是一种优化技术,次要用于通过存储低廉的函数调用的后果并在再次出现雷同的输出时返回缓存的后果来减速计算机程序。

Memoization 也已用于其余上下文(以及速度增益以外的目标),例如在简略的互相递归降落解析中。只管与缓存无关,但记忆化是指此优化的特定状况,将其与缓存或页面替换等缓存模式辨别开来。在某些逻辑编程语言的上下文中,记忆化也称为 Tabling.

记忆性能“记住”与某些特定输出集绝对应的后果。应用记住输出的后续调用返回记住的后果而不是从新计算它,从而打消了应用给定参数调用的次要老本,除了第一次应用这些参数调用函数。记住的关联集能够是由替换算法管制的固定大小的集,也能够是固定集,这取决于函数的性质及其用处。一个函数只有在援用通明的状况下能力被记忆;也就是说,仅当调用该函数与用其返回值替换该函数调用具备完全相同的成果时。 (然而,存在此限度的非凡状况例外。)尽管与查找表相干,但因为记忆在其实现中常常应用此类表,因而记忆会依据须要即时而不是提前填充其后果缓存。

记忆化是一种以就义空间老本的办法来升高函数工夫老本的优化形式;也就是说,记忆化的函数会针对速度进行优化,付出的代价是对计算机内存空间的更高使用率。算法的工夫/空间“老本”在计算中有一个特定的名称:计算复杂度。所有函数在工夫(即它们须要工夫来执行)和空间上都具备计算复杂性。

什么是 NgRx selector

选择器是用于获取存储状态切片( store state slices)的纯函数。@ngrx/store 提供了一些帮忙函数来优化这个抉择。

Selector 也合乎繁多职责及 Single responsibility,一个 selector 只 touch State 的一个片段。

应用 createSelector 和 createFeatureSelector 函数时,@ngrx/store 会跟踪调用选择器函数的最新参数。 因为选择器是纯函数,当参数匹配时能够返回最初一个后果,而无需从新调用选择器函数。这能够提供性能劣势,特地是对于执行低廉计算的选择器。这种做法被称为记忆。

换言之,咱们尽管实现了 Selector,然而运行时,这些 selector 可能只会被执行一次,因为如果输出参数雷同,NgRx 框架会应用缓存的后果间接返回给调用者,而不会反复调用咱们的 Selector.

例子:Using a selector for one piece of state

import { createSelector } from '@ngrx/store';export interface FeatureState {  counter: number;}export interface AppState {  feature: FeatureState;}export const selectFeature = (state: AppState) => state.feature;export const selectFeatureCount = createSelector(  selectFeature,  (state: FeatureState) => state.counter);console.log('ok');

例子:Using selectors for multiple pieces of state

createSelector 可用于基于雷同状态(State)的多个切片从状态中抉择一些数据。

createSelector 函数最多能够应用 8 个选择器函数,用于更残缺的状态抉择。

例如,假如您在状态中有一个 selectedUser 对象。 您还有一个 allBooks 书籍对象数组。

并且您想显示以后用户的所有书籍。

您能够应用 createSelector 来实现这一点。即便您在 allBooks 中更新它们,您的可见书籍也将始终是最新的。 如果抉择了一个,它们将始终显示属于您的用户的书籍,如果没有抉择用户,它们将显示所有书籍。

CreateSelector 里传入纯函数。

import { createSelector } from '@ngrx/store';export interface User {  id: number;  name: string;}export interface Book {  id: number;  userId: number;  name: string;}export interface AppState {  selectedUser: User;  allBooks: Book[];}export const selectUser = (state: AppState) => state.selectedUser;export const selectAllBooks = (state: AppState) => state.allBooks;export const selectVisibleBooks = createSelector(  selectUser,  selectAllBooks,  (selectedUser: User, allBooks: Book[]) => {    if (selectedUser && allBooks) {      return allBooks.filter((book: Book) => book.userId === selectedUser.id);    } else {      return allBooks;    }  });

Selecting Feature States

createFeatureSelector 是返回顶级性能状态(Top Level Feature State)的便捷办法。它为状态的特色切片返回一个类型化的选择器函数。

import { createSelector, createFeatureSelector } from '@ngrx/store';export const featureKey = 'feature';export interface FeatureState {  counter: number;}export interface AppState {  feature: FeatureState;}export const selectFeature = createFeatureSelector<AppState, FeatureState>(featureKey);export const selectFeatureCount = createSelector(  selectFeature,  (state: FeatureState) => state.counter);

Resetting Memoized Selectors

通过调用 createSelector 或 createFeatureSelector 返回的选择器函数最后的记忆值为 null。 在第一次调用选择器后,其记忆值存储在内存中。 如果随后应用雷同的参数调用选择器,它将返回记忆值。 如果随后应用不同的参数调用选择器,它将从新计算并更新其记忆值。

一个例子:

import { createSelector } from '@ngrx/store';export interface State {  counter1: number;  counter2: number;}export const selectCounter1 = (state: State) => state.counter1;export const selectCounter2 = (state: State) => state.counter2;export const selectTotal = createSelector(  selectCounter1,  selectCounter2,  (counter1, counter2) => counter1 + counter2); // selectTotal has a memoized value of null, because it has not yet been invoked.let state = { counter1: 3, counter2: 4 };selectTotal(state); // computes the sum of 3 & 4, returning 7. selectTotal now has a memoized value of 7selectTotal(state); // does not compute the sum of 3 & 4. selectTotal instead returns the memoized value of 7state = { ...state, counter2: 5 };selectTotal(state); // computes the sum of 3 & 5, returning 8. selectTotal now has a memoized value of 8

选择器的记忆值无限期地保留在内存中。 例如,如果记忆值是不再须要的大数据集,则能够将记忆值重置为 null,以便能够从内存中删除大数据集。 这能够通过调用选择器上的 release 办法来实现。

selectTotal(state); // returns the memoized value of 8selectTotal.release(); // memoized value of selectTotal is now null