Skip to content

Commit

Permalink
fix(perf): improve long running task performance in query core (#8107)
Browse files Browse the repository at this point in the history
* fix: improve long running task performance in query core

This addresses two hot spots we have noticed
on a large scale enterprise app when profiling
with chrome. These changes help to cut down
on long running tasks when there are many query
calls on the page

* refactor: remove two more arrays to be more efficient

* refactor: remove queryObserver improvement from PR

* refactor: packages/query-core/src/queryObserver.ts remove

---------

Co-authored-by: davidaghassi <davidaghassi@robinhood.com>
Co-authored-by: Dominik Dorfmeister <office@dorfmeister.cc>
  • Loading branch information
3 people authored Oct 9, 2024
1 parent 44b70f1 commit 5499577
Showing 1 changed file with 30 additions and 46 deletions.
76 changes: 30 additions & 46 deletions packages/query-core/src/queriesObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,59 +207,43 @@ export class QueriesObserver<
#findMatchingObservers(
queries: Array<QueryObserverOptions>,
): Array<QueryObserverMatch> {
const prevObservers = this.#observers
const prevObserversMap = new Map(
prevObservers.map((observer) => [observer.options.queryHash, observer]),
this.#observers.map((observer) => [observer.options.queryHash, observer]),
)

const defaultedQueryOptions = queries.map((options) =>
this.#client.defaultQueryOptions(options),
)

const matchingObservers: Array<QueryObserverMatch> =
defaultedQueryOptions.flatMap((defaultedOptions) => {
const match = prevObserversMap.get(defaultedOptions.queryHash)
if (match != null) {
return [{ defaultedQueryOptions: defaultedOptions, observer: match }]
}
return []
})

const matchedQueryHashes = new Set(
matchingObservers.map((match) => match.defaultedQueryOptions.queryHash),
)
const unmatchedQueries = defaultedQueryOptions.filter(
(defaultedOptions) => !matchedQueryHashes.has(defaultedOptions.queryHash),
)
const observers: Array<QueryObserverMatch> = []

const getObserver = (options: QueryObserverOptions): QueryObserver => {
queries.forEach((options) => {
const defaultedOptions = this.#client.defaultQueryOptions(options)
const currentObserver = this.#observers.find(
(o) => o.options.queryHash === defaultedOptions.queryHash,
)
const match = prevObserversMap.get(defaultedOptions.queryHash)
if (match) {
observers.push({
defaultedQueryOptions: defaultedOptions,
observer: match,
})
} else {
const existingObserver = this.#observers.find(
(o) => o.options.queryHash === defaultedOptions.queryHash,
)
observers.push({
defaultedQueryOptions: defaultedOptions,
observer:
existingObserver ??
new QueryObserver(this.#client, defaultedOptions),
})
}
})

return observers.sort((a, b) => {
return (
currentObserver ?? new QueryObserver(this.#client, defaultedOptions)
queries.findIndex(
(q) => q.queryHash === a.defaultedQueryOptions.queryHash,
) -
queries.findIndex(
(q) => q.queryHash === b.defaultedQueryOptions.queryHash,
)
)
}

const newOrReusedObservers: Array<QueryObserverMatch> =
unmatchedQueries.map((options) => {
return {
defaultedQueryOptions: options,
observer: getObserver(options),
}
})

const sortMatchesByOrderOfQueries = (
a: QueryObserverMatch,
b: QueryObserverMatch,
): number =>
defaultedQueryOptions.indexOf(a.defaultedQueryOptions) -
defaultedQueryOptions.indexOf(b.defaultedQueryOptions)

return matchingObservers
.concat(newOrReusedObservers)
.sort(sortMatchesByOrderOfQueries)
})
}

#onUpdate(observer: QueryObserver, result: QueryObserverResult): void {
Expand Down

0 comments on commit 5499577

Please sign in to comment.