Skip to content
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

perf: Use @@toStringTag and Map for better perf #12491

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

ShuiRuTian
Copy link

There are 2 macro optimizations:

  1. Use instanceof rather than toString, this is about 100% faster, and makes things more accurate.
  2. Use Map rather than Object, this is about 30% faster.

However, I am not sure about isPromise. According to the name, it only want to judge whether it's a Promise or not. But current logic is to judge whether it's thennable. This might be a breaking change.

…her than object to be faster and more accurate
@Justineo
Copy link
Member

Justineo commented Dec 1, 2024

instanceof cannot work across <iframe> boundaries. Using Object.prototype.toString is a common alternative to determine the type of an object. This covers more use cases.

@ShuiRuTian
Copy link
Author

ShuiRuTian commented Dec 1, 2024

@Justineo Thanks. I hardly use iframe and did not think about them...

Use Symbol.toStringTag instead if possible, and it's even faster. However, I found the profiling time vary a lot on my local machine, is there some robot I could call out to profile?

@ShuiRuTian ShuiRuTian changed the title Use instanceof and Map for better perf Use @@toStringTag and Map for better perf Dec 1, 2024
@Justineo
Copy link
Member

Justineo commented Dec 1, 2024

You could consider setting up some benchmarks on platforms like jsbench.me.

@edison1105 edison1105 added the need more info Further information is requested label Dec 1, 2024
@ShuiRuTian
Copy link
Author

ShuiRuTian commented Dec 1, 2024

Here is my benchmark example: https://jsbench.me/krm45pp7nd/1

And here is the result:

  • Current: 2266万 ops/s ± 3.28%
  • instanceof: 2.3亿 ops/s ± 1.22%
  • @@toStringTag: 2.2亿 ops/s ± 2.1%

Looks good.

And here is benchmark comparation result, I only picked the result that is changed larger than 5% and rme is less than 1%:

I do not know which part is important, but it looks good to me, especially there are 3 cases that improves 20%+

   · write ref, read computed (with effect)                         7,683,786.00  0.0001  0.3473  0.0001  0.0002  0.0002  0.0003  0.0004  ±0.24%   3841893  [0.93x] ⇓
     write ref, read computed (with effect)                         8,265,654.35  0.0001  0.7701  0.0001  0.0001  0.0002  0.0003  0.0004  ±0.80%   4132828  (baseline)
   · write ref, don't read 1000 computeds (without effect)         22,545,853.49  0.0000  0.4810  0.0000  0.0001  0.0001  0.0001  0.0003  ±0.30%  11272929  [1.06x] ⇑
     write ref, don't read 1000 computeds (without effect)         21,235,565.75  0.0000  0.8568  0.0000  0.0001  0.0001  0.0001  0.0003  ±0.61%  10617785  (baseline)
   · write ref, read 1000 computeds (with multiple effects)            13,229.05  0.0680  0.9690  0.0756  0.0739  0.1381  0.1837  0.3030  ±0.64%      6615  [0.91x] ⇓
     write ref, read 1000 computeds (with multiple effects)            14,535.18  0.0650  0.2618  0.0688  0.0684  0.0814  0.0944  0.1181  ±0.15%      7268  (baseline)
   · 1000 refs, read 1 computed (with effect)                          57,845.38  0.0153  0.3155  0.0173  0.0177  0.0258  0.0286  0.0484  ±0.25%     28923  [0.94x] ⇓
     1000 refs, read 1 computed (with effect)                          61,730.02  0.0148  0.1841  0.0162  0.0166  0.0229  0.0245  0.0271  ±0.11%     30866  (baseline)
   · write reactive map, don't read computed (invoked)              6,280,659.49  0.0001   0.0844  0.0002  0.0002  0.0003  0.0003  0.0005   ±0.10%  3140331  [1.36x] ⇑
     write reactive map, don't read computed (invoked)              4,616,937.08  0.0001   0.3780  0.0002  0.0002  0.0004  0.0005  0.0007   ±0.46%  2308469  (baseline)
   · write reactive map, read computed                              3,317,786.00  0.0002   0.1023  0.0003  0.0003  0.0005  0.0005  0.0008   ±0.08%  1658893  [1.21x] ⇑
     write reactive map, read computed                              2,751,338.35  0.0003   0.2377  0.0004  0.0004  0.0007  0.0008  0.0010   ±0.35%  1375670  (baseline)
   · write reactive map, don't read 1000 computeds (invoked)        5,989,028.00  0.0001   0.0963  0.0002  0.0002  0.0003  0.0004  0.0005   ±0.10%  2994514  [1.41x] ⇑
     write reactive map, don't read 1000 computeds (invoked)        4,245,770.30  0.0001   1.2880  0.0002  0.0003  0.0004  0.0005  0.0007   ±0.84%  2122886  (baseline)
   · 1 ref invoking 10 effects                         3,628,439.27   0.0002   0.3025   0.0003   0.0003   0.0005   0.0005   0.0007  ±0.38%  1814220  [1.10x] ⇑
     1 ref invoking 10 effects                         3,289,414.00   0.0002   0.1333   0.0003   0.0003   0.0004   0.0005   0.0007  ±0.14%  1644707  (baseline)
   · 1 ref invoking 100 effects                          410,433.67   0.0023   0.2580   0.0024   0.0024   0.0028   0.0036   0.0048  ±0.12%   205217  [1.10x] ⇑
     1 ref invoking 100 effects                          374,439.98   0.0025   1.0689   0.0027   0.0027   0.0035   0.0042   0.0051  ±0.43%   187221  (baseline)
   · update ref to trigger watchEffect (scheduled but not executed)  2,781,636.33  0.0002  0.1086  0.0004  0.0004  0.0007  0.0008  0.0010  ±0.10%  1390819  [1.06x] ⇑
     update ref to trigger watchEffect (scheduled but not executed)  2,628,404.42  0.0003  0.1979  0.0004  0.0004  0.0007  0.0008  0.0009  ±0.13%  1314203  (baseline)
   · read reactive obj property   14,950,800.00  0.0000  0.2837  0.0001  0.0001  0.0001  0.0002  0.0003   ±0.30%  7475400  [1.07x] ⇑
     read reactive obj property   13,940,586.00  0.0000  0.2386  0.0001  0.0001  0.0001  0.0001  0.0003   ±0.24%  6970293  (baseline)

Copy link

github-actions bot commented Dec 2, 2024

Size Report

Bundles

File Size Gzip Brotli
runtime-dom.global.prod.js 100 kB (+144 B) 38 kB (+27 B) 34.3 kB (+55 B)
vue.global.prod.js 158 kB (+142 B) 57.8 kB (+33 B) 51.5 kB (+54 B)

Usages

Name Size Gzip Brotli
createApp (CAPI only) 47.2 kB (+76 B) 18.4 kB (+9 B) 16.8 kB (+17 B)
createApp 55.3 kB (+89 B) 21.4 kB (+14 B) 19.5 kB (+24 B)
createSSRApp 59.4 kB (+91 B) 23.1 kB (+17 B) 21 kB (+13 B)
defineCustomElement 60.2 kB (+91 B) 22.9 kB (+11 B) 20.9 kB (+31 B)
overall 69.2 kB (+87 B) 26.5 kB (+8 B) 24.1 kB (+25 B)

Copy link

pkg-pr-new bot commented Dec 2, 2024

Open in Stackblitz

@vue/compiler-core

npm i https://pkg.pr.new/@vue/compiler-core@12491

@vue/compiler-dom

npm i https://pkg.pr.new/@vue/compiler-dom@12491

@vue/compiler-sfc

npm i https://pkg.pr.new/@vue/compiler-sfc@12491

@vue/compiler-ssr

npm i https://pkg.pr.new/@vue/compiler-ssr@12491

@vue/runtime-core

npm i https://pkg.pr.new/@vue/runtime-core@12491

@vue/reactivity

npm i https://pkg.pr.new/@vue/reactivity@12491

@vue/runtime-dom

npm i https://pkg.pr.new/@vue/runtime-dom@12491

@vue/server-renderer

npm i https://pkg.pr.new/@vue/server-renderer@12491

@vue/shared

npm i https://pkg.pr.new/@vue/shared@12491

vue

npm i https://pkg.pr.new/vue@12491

@vue/compat

npm i https://pkg.pr.new/@vue/compat@12491

commit: c46cd24

@edison1105
Copy link
Member

/ecosystem-ci run

@vue-bot
Copy link
Contributor

vue-bot commented Dec 5, 2024

📝 Ran ecosystem CI: Open

suite result latest scheduled
language-tools failure failure
nuxt failure failure
pinia success success
primevue success success
quasar success success
radix-vue success success
router success success
test-utils success success
vant success success
vite-plugin-vue success success
vitepress success success
vue-i18n success success
vue-macros success success
vuetify success success
vueuse success success
vue-simple-compiler success success

@edison1105 edison1105 changed the title Use @@toStringTag and Map for better perf perf: Use @@toStringTag and Map for better perf Dec 5, 2024
@edison1105
Copy link
Member

Use Map rather than Object, this is about 30% faster.

I got different performance data, see https://measurethat.net/Benchmarks/Show/32894/1/test-map-vs-object

@ShuiRuTian
Copy link
Author

ShuiRuTian commented Dec 5, 2024

@edison1105

here is my 5 cents about benchmark:
https://measurethat.net/Benchmarks/Show/32902/0/test-map-vs-object-with-string-which-use-string-as-key

For set-value, the perf is similar, for get-value, Map is 200% faster(wow...) as shown in this case. If for the cache in Vue, the key is more frequently to be different with the key last time visited, then this test case might reflect real world better.

@edison1105 edison1105 added ready to merge The PR is ready to be merged. 🧹 p1-chore Priority 1: this doesn't change code behavior. and removed need more info Further information is requested labels Dec 6, 2024
@edison1105
Copy link
Member

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🧹 p1-chore Priority 1: this doesn't change code behavior. ready to merge The PR is ready to be merged.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants