From f94fc1667024e012eb5233e4c2c6cd35a2b09a51 Mon Sep 17 00:00:00 2001 From: Mark Erikson Date: Tue, 23 Apr 2024 00:09:12 +0200 Subject: [PATCH] Try speeding up entity adapter by minimizing Immer reads --- .../src/entities/sorted_state_adapter.ts | 53 ++++++++++++++----- packages/toolkit/src/entities/utils.ts | 11 ++-- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/packages/toolkit/src/entities/sorted_state_adapter.ts b/packages/toolkit/src/entities/sorted_state_adapter.ts index aef9ff20bb..195345cb87 100644 --- a/packages/toolkit/src/entities/sorted_state_adapter.ts +++ b/packages/toolkit/src/entities/sorted_state_adapter.ts @@ -65,11 +65,17 @@ export function createSortedStateAdapter( function addManyMutably( newEntities: readonly T[] | Record, state: R, + existingIds?: Id[], ): void { newEntities = ensureEntitiesArray(newEntities) + const existingKeys = new Set( + existingIds ?? (current(state.ids) as Id[]), + ) + const models = newEntities.filter( - (model) => !(selectIdValue(model, selectId) in state.entities), + // (model) => !(selectId(model) in state.entities), + (model) => !existingKeys.has(selectIdValue(model, selectId)), ) if (models.length !== 0) { @@ -103,7 +109,7 @@ export function createSortedStateAdapter( state.entities = {} as Record state.ids = [] - addManyMutably(newEntities, state) + addManyMutably(newEntities, state, []) } function updateOneMutably(update: Update, state: R): void { @@ -153,14 +159,18 @@ export function createSortedStateAdapter( newEntities: readonly T[] | Record, state: R, ): void { - const [added, updated] = splitAddedUpdatedEntities( + const [added, updated, existingIdsArray] = splitAddedUpdatedEntities( newEntities, selectId, state, ) - updateManyMutably(updated, state) - addManyMutably(added, state) + if (updated.length) { + updateManyMutably(updated, state) + } + if (added.length) { + addManyMutably(added, state, existingIdsArray) + } } function areArraysEqual(a: readonly unknown[], b: readonly unknown[]) { @@ -311,10 +321,14 @@ export function createSortedStateAdapter( updatedIds, replacedIds, ) => { - const entities = state.entities as Record - let ids = state.ids as Id[] + const currentEntities = current(state.entities) as Record + const currentIds = current(state.ids) as Id[] + // const entities = state.entities as Record + const stateEntities = state.entities as Record + // let ids = state.ids as Id[] + let ids = currentIds if (replacedIds) { - ids = Array.from(new Set(ids)) + ids = Array.from(new Set(currentIds)) } // //let sortedEntities: T[] = [] @@ -335,9 +349,16 @@ export function createSortedStateAdapter( // } // } // } - let sortedEntities = ids // Array.from(new Set(state.ids as Id[])) - .map((id) => entities[id]) - .filter(Boolean) + let sortedEntities: T[] = [] + for (const id of ids) { + const entity = currentEntities[id] + if (entity) { + sortedEntities.push(entity) + } + } + // let sortedEntities = ids // Array.from(new Set(state.ids as Id[])) + // .map((id) => currentEntities[id]) + // .filter(Boolean) const wasPreviouslyEmpty = sortedEntities.length === 0 @@ -356,7 +377,7 @@ export function createSortedStateAdapter( // Insert/overwrite all new/updated for (const item of addedItems) { - entities[selectId(item)] = item + stateEntities[selectId(item)] = item // console.log('Inserting: ', isDraft(item) ? current(item) : item) if (!wasPreviouslyEmpty) { insert(sortedEntities, item, comparer) @@ -366,12 +387,18 @@ export function createSortedStateAdapter( if (wasPreviouslyEmpty) { sortedEntities = addedItems.slice().sort(comparer) } else if (updatedIds?.size) { + for (const updatedId of updatedIds) { + const item: T = currentEntities[updatedId] + // const currentIndex = sortedEntities.indexOf(item) + // const newIndex = findInsertIndex(sortedEntities, item, comparer) + // console.log('Item: ', updatedId, { currentIndex, newIndex }) + } sortedEntities.sort(comparer) } const newSortedIds = sortedEntities.map(selectId) // console.log('New sorted IDs: ', newSortedIds) - if (!areArraysEqual(state.ids, newSortedIds)) { + if (!areArraysEqual(currentIds, newSortedIds)) { state.ids = newSortedIds } } diff --git a/packages/toolkit/src/entities/utils.ts b/packages/toolkit/src/entities/utils.ts index 5e3fb92fc1..fce14d586d 100644 --- a/packages/toolkit/src/entities/utils.ts +++ b/packages/toolkit/src/entities/utils.ts @@ -1,3 +1,4 @@ +import { current } from 'immer' import type { IdSelector, Update, @@ -39,19 +40,23 @@ export function splitAddedUpdatedEntities( newEntities: readonly T[] | Record, selectId: IdSelector, state: DraftableEntityState, -): [T[], Update[]] { +): [T[], Update[], Id[]] { newEntities = ensureEntitiesArray(newEntities) + const existingIdsArray = current(state.ids) as Id[] + const existingIds = new Set(existingIdsArray) + const added: T[] = [] const updated: Update[] = [] for (const entity of newEntities) { const id = selectIdValue(entity, selectId) - if (id in state.entities) { + if (existingIds.has(id)) { + // if (id in state.entities) { updated.push({ id, changes: entity }) } else { added.push(entity) } } - return [added, updated] + return [added, updated, existingIdsArray] }