Skip to content

Commit 7d24156

Browse files
Sheraffautofix-ci[bot]TkDodo
authored
refactor(query-core): improve replaceEqualDeep performance (#9604)
* refactor(query-core): improve replaceEqualDeep performance * try object.prototype that broke eslint in router * no object flag * improved version w/ more code * ci: apply automated fixes * less code, but still 2x faster --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Dominik Dorfmeister <office@dorfmeister.cc>
1 parent f97d725 commit 7d24156

File tree

1 file changed

+37
-30
lines changed

1 file changed

+37
-30
lines changed

packages/query-core/src/utils.ts

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ export function partialMatchKey(a: any, b: any): boolean {
245245
return false
246246
}
247247

248+
const hasOwn = Object.prototype.hasOwnProperty
249+
248250
/**
249251
* This function returns `a` if `b` is deeply equal.
250252
* If not, it will replace any deeply equal children of `b` with those of `a`.
@@ -258,37 +260,43 @@ export function replaceEqualDeep(a: any, b: any): any {
258260

259261
const array = isPlainArray(a) && isPlainArray(b)
260262

261-
if (array || (isPlainObject(a) && isPlainObject(b))) {
262-
const aItems = array ? a : Object.keys(a)
263-
const aSize = aItems.length
264-
const bItems = array ? b : Object.keys(b)
265-
const bSize = bItems.length
266-
const copy: any = array ? [] : {}
267-
const aItemsSet = new Set(aItems)
268-
269-
let equalItems = 0
270-
271-
for (let i = 0; i < bSize; i++) {
272-
const key = array ? i : bItems[i]
273-
if (
274-
((!array && aItemsSet.has(key)) || array) &&
275-
a[key] === undefined &&
276-
b[key] === undefined
277-
) {
278-
copy[key] = undefined
279-
equalItems++
280-
} else {
281-
copy[key] = replaceEqualDeep(a[key], b[key])
282-
if (copy[key] === a[key] && a[key] !== undefined) {
283-
equalItems++
284-
}
285-
}
263+
if (!array && !(isPlainObject(a) && isPlainObject(b))) return b
264+
265+
const aItems = array ? a : Object.keys(a)
266+
const aSize = aItems.length
267+
const bItems = array ? b : Object.keys(b)
268+
const bSize = bItems.length
269+
const copy: any = array ? new Array(bSize) : {}
270+
271+
let equalItems = 0
272+
273+
for (let i = 0; i < bSize; i++) {
274+
const key: any = array ? i : bItems[i]
275+
const aItem = a[key]
276+
const bItem = b[key]
277+
278+
if (aItem === bItem) {
279+
copy[key] = aItem
280+
if (array ? i < aSize : hasOwn.call(a, key)) equalItems++
281+
continue
282+
}
283+
284+
if (
285+
aItem === null ||
286+
bItem === null ||
287+
typeof aItem !== 'object' ||
288+
typeof bItem !== 'object'
289+
) {
290+
copy[key] = bItem
291+
continue
286292
}
287293

288-
return aSize === bSize && equalItems === aSize ? a : copy
294+
const v = replaceEqualDeep(aItem, bItem)
295+
copy[key] = v
296+
if (v === aItem) equalItems++
289297
}
290298

291-
return b
299+
return aSize === bSize && equalItems === aSize ? a : copy
292300
}
293301

294302
/**
@@ -311,13 +319,12 @@ export function shallowEqualObjects<T extends Record<string, any>>(
311319
return true
312320
}
313321

314-
export function isPlainArray(value: unknown) {
322+
export function isPlainArray(value: unknown): value is Array<unknown> {
315323
return Array.isArray(value) && value.length === Object.keys(value).length
316324
}
317325

318326
// Copied from: https://github.com/jonschlinkert/is-plain-object
319-
// eslint-disable-next-line @typescript-eslint/no-wrapper-object-types
320-
export function isPlainObject(o: any): o is Object {
327+
export function isPlainObject(o: any): o is Record<PropertyKey, unknown> {
321328
if (!hasObjectPrototype(o)) {
322329
return false
323330
}

0 commit comments

Comments
 (0)