-
-
Notifications
You must be signed in to change notification settings - Fork 8.6k
fix(apiWatch): deep watch should support symbols, performance tweaks #402
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -234,17 +234,26 @@ function traverse(value: unknown, seen: Set<unknown> = new Set()) { | |
traverse(value[i], seen) | ||
} | ||
} else if (value instanceof Map) { | ||
value.forEach((v, key) => { | ||
// to register mutation dep for existing keys | ||
traverse(value.get(key), seen) | ||
}) | ||
const keys = [...value.keys()] | ||
|
||
for (let i = 0; i < keys.length; i++) { | ||
traverse(value.get(keys[i]), seen) | ||
} | ||
} else if (value instanceof Set) { | ||
value.forEach(v => { | ||
traverse(v, seen) | ||
}) | ||
const values = [...value.values()] | ||
|
||
for (let i = 0; i < values.length; i++) { | ||
traverse(values[i], seen) | ||
} | ||
} else { | ||
for (const key in value) { | ||
traverse(value[key], seen) | ||
const keys = [ | ||
...Object.getOwnPropertyNames(value), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if this should be the case here. This would iterate over non-enumerable properties too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the technically correct implementation here is using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can try to make a benchmark just as in upper comment :). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Benchmark (anything as the first comment): FF: Node: Results of this benchmark are questionable, and I think both of these should be validated in e.g. a CI env, since my CPU frequency and load isn't really stable. Code: function forInObject (val) {
console.time('for...in')
console.groupCollapsed('data')
for (const x in val) {
console.log(x)
}
console.groupEnd()
console.timeEnd('for...in')
}
function forSpreadSet (val) {
console.time('for with spread keys')
console.groupCollapsed('data')
const arr = [...Object.keys(val)]
for (let i = 0; i < arr.length; i++) {
console.log(arr[i])
}
console.groupEnd()
console.timeEnd('for with spread keys')
}
const obj1 = { '1': 1, '2': 2, '3': 3 }
const obj2 = {}
for (let i = 0; i < 100; i++) {
obj2[i] = i
}
const obj3 = {}
for (let i = 0; i < 10000; i++) {
obj3[i] = i
}
forInObject(obj1)
forSpreadSet(obj1)
forInObject(obj2)
forSpreadSet(obj2)
forInObject(obj3)
forSpreadSet(obj3) |
||
...Object.getOwnPropertySymbols(value) | ||
] | ||
|
||
for (let i = 0; i < keys.length; i++) { | ||
// TS doesn't allow symbol as index type | ||
traverse(value[keys[i] as string], seen) | ||
} | ||
} | ||
return value | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cost here is almost the same because it involves spreading the iterator into a plain array. The array spread can often be deceivingly expensive. Not really worth it IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested set iterating in some browsers:
Chrome 79.0.3941.4 (64 bit, V8 7.9.293)
Firefox 70.0 (64 bit) (
мс
stands for millisecond in Russian,таймер закончился
= timer ended)I ran tests in Node too, but I had to call functions separately since console gets clogged but I don't want to change the task:
Node v12.8.0 (64 bit):
I loaded the same start code:

Small set:

100 elements:


Now, 10k elements:


So, spread method gives better performance than
for...of
, but (why?) was worse in Chrome and Node with 100-element setCode:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On my side I see no significant difference even with a million items in the set. I've looked at both timing and memory performance indicators, refreshing the page for each particular method (so run test with spread, change code to for..of and refresh, a few times over).
Chrome Version 79.0.3945.88 (Official Build) (64-bit) on MacOS Catalina (10.14.6) (spec 2.4GHz i5, 16GB 2133MHz LPDDR3) by launching chrome with:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --enable-precise-memory-info --js-flags="--trace-opt --trace-deopt"
The timing varies with each refresh in a range of 30 to 45 ms, regardless of the loop method being used.