├── .gitignore
├── index.html
├── package.json
├── src
├── computed.js
├── main.js
├── mix.js
├── reactiveArray.js
├── reactiveMap.js
├── reactiveObject.js
├── ref.js
├── watch.js
└── watchEffect.js
└── vue.global.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # We don't need to share config
2 | .idea
3 |
4 | # Created by https://www.gitignore.io/api/node,intellij
5 | # Edit at https://www.gitignore.io/?templates=node,intellij
6 |
7 | ### Intellij ###
8 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
9 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
10 |
11 | # User-specific stuff
12 | .idea/**/workspace.xml
13 | .idea/**/tasks.xml
14 | .idea/**/usage.statistics.xml
15 | .idea/**/dictionaries
16 | .idea/**/shelf
17 |
18 | # Generated files
19 | .idea/**/contentModel.xml
20 |
21 | # Sensitive or high-churn files
22 | .idea/**/dataSources/
23 | .idea/**/dataSources.ids
24 | .idea/**/dataSources.local.xml
25 | .idea/**/sqlDataSources.xml
26 | .idea/**/dynamic.xml
27 | .idea/**/uiDesigner.xml
28 | .idea/**/dbnavigator.xml
29 |
30 | # Gradle
31 | .idea/**/gradle.xml
32 | .idea/**/libraries
33 |
34 | # Gradle and Maven with auto-import
35 | # When using Gradle or Maven with auto-import, you should exclude module files,
36 | # since they will be recreated, and may cause churn. Uncomment if using
37 | # auto-import.
38 | .idea/modules.xml
39 | .idea/*.iml
40 | .idea/modules
41 | *.iml
42 | *.ipr
43 |
44 | # CMake
45 | cmake-build-*/
46 |
47 | # Mongo Explorer plugin
48 | .idea/**/mongoSettings.xml
49 |
50 | # File-based project format
51 | *.iws
52 |
53 | # IntelliJ
54 | out/
55 |
56 | # mpeltonen/sbt-idea plugin
57 | .idea_modules/
58 |
59 | # JIRA plugin
60 | atlassian-ide-plugin.xml
61 |
62 | # Cursive Clojure plugin
63 | .idea/replstate.xml
64 |
65 | # Crashlytics plugin (for Android Studio and IntelliJ)
66 | com_crashlytics_export_strings.xml
67 | crashlytics.properties
68 | crashlytics-build.properties
69 | fabric.properties
70 |
71 | # Editor-based Rest Client
72 | .idea/httpRequests
73 |
74 | # Android studio 3.1+ serialized cache file
75 | .idea/caches/build_file_checksums.ser
76 |
77 | ### Intellij Patch ###
78 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
79 |
80 | # *.iml
81 | # modules.xml
82 | # .idea/misc.xml
83 | # *.ipr
84 |
85 | # Sonarlint plugin
86 | .idea/**/sonarlint/
87 |
88 | # SonarQube Plugin
89 | .idea/**/sonarIssues.xml
90 |
91 | # Markdown Navigator plugin
92 | .idea/**/markdown-navigator.xml
93 | .idea/**/markdown-navigator/
94 |
95 | ### Node ###
96 | # Logs
97 | logs
98 | *.log
99 | npm-debug.log*
100 | yarn-debug.log*
101 | yarn-error.log*
102 | lerna-debug.log*
103 |
104 | # Diagnostic reports (https://nodejs.org/api/report.html)
105 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
106 |
107 | # Runtime data
108 | pids
109 | *.pid
110 | *.seed
111 | *.pid.lock
112 |
113 | # Directory for instrumented libs generated by jscoverage/JSCover
114 | lib-cov
115 |
116 | # Coverage directory used by tools like istanbul
117 | coverage
118 | *.lcov
119 |
120 | # nyc test coverage
121 | .nyc_output
122 |
123 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
124 | .grunt
125 |
126 | # Bower dependency directory (https://bower.io/)
127 | bower_components
128 |
129 | # node-waf configuration
130 | .lock-wscript
131 |
132 | # Compiled binary addons (https://nodejs.org/api/addons.html)
133 | build/Release
134 |
135 | # Dependency directories
136 | node_modules/
137 | jspm_packages/
138 |
139 | # TypeScript v1 declaration files
140 | typings/
141 |
142 | # TypeScript cache
143 | *.tsbuildinfo
144 |
145 | # Optional npm cache directory
146 | .npm
147 |
148 | # Optional eslint cache
149 | .eslintcache
150 |
151 | # Optional REPL history
152 | .node_repl_history
153 |
154 | # Output of 'npm pack'
155 | *.tgz
156 |
157 | # Yarn Integrity file
158 | .yarn-integrity
159 |
160 | # dotenv environment variables file
161 | .env
162 | .env.test
163 |
164 | # parcel-bundler cache (https://parceljs.org/)
165 | .cache
166 |
167 | # next.js build output
168 | .next
169 |
170 | # nuxt.js build output
171 | .nuxt
172 |
173 | # rollup.js default build output
174 | dist/
175 |
176 | # Uncomment the public line if your project uses Gatsby
177 | # https://nextjs.org/blog/next-9-1#public-directory-support
178 | # https://create-react-app.dev/docs/using-the-public-folder/#docsNav
179 | # public
180 |
181 | # Storybook build outputs
182 | .out
183 | .storybook-out
184 |
185 | # vuepress build output
186 | .vuepress/dist
187 |
188 | # Serverless directories
189 | .serverless/
190 |
191 | # FuseBox cache
192 | .fusebox/
193 |
194 | # DynamoDB Local files
195 | .dynamodb/
196 |
197 | # Temporary folders
198 | tmp/
199 | temp/
200 |
201 | # End of https://www.gitignore.io/api/node,intellij
202 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vue tests
8 |
9 |
10 |
11 |
12 |
60 |
61 |
62 | Vue3 benchmarks
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | Link usage:
?v=3.0.0-rc.12&b=ref,computed
83 |
84 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-next-benchmarks",
3 | "version": "1.0.0",
4 | "description": "Benchmarks Vue3 core features, to keep track of performance",
5 | "main": "index.js",
6 | "author": "Bas van Meurs, bvanmeurs1985@gmail.com",
7 | "license": "MIT"
8 | }
9 |
--------------------------------------------------------------------------------
/src/computed.js:
--------------------------------------------------------------------------------
1 | function go() {
2 | const { ref, computed, watch, watchEffect } = Vue;
3 |
4 | const suite = new Benchmark.Suite();
5 |
6 | bench(() => {
7 | return suite.add("create computed", () => {
8 | const c = computed(() => 100);
9 | });
10 | });
11 |
12 | bench(() => {
13 | let i = 0;
14 | const o = ref(100);
15 | return suite.add("write independent ref dep", () => {
16 | o.value = i++;
17 | });
18 | });
19 |
20 | bench(() => {
21 | const v = ref(100);
22 | const c = computed(() => {
23 | return v.value * 2
24 | });
25 | let i = 0;
26 | return suite.add("write ref, don't read computed (never invoked)", () => {
27 | v.value = i++;
28 | });
29 | })
30 |
31 | bench(() => {
32 | const v = ref(100);
33 | const c = computed(() => {
34 | return v.value * 2
35 | });
36 | const cv = c.value;
37 | let i = 0;
38 | return suite.add("write ref, don't read computed (invoked)", () => {
39 | v.value = i++;
40 | });
41 | })
42 |
43 | bench(() => {
44 | const v = ref(100);
45 | const c = computed(() => {
46 | return v.value * 2
47 | });
48 | let i = 0;
49 | return suite.add("write ref, read computed", () => {
50 | v.value = i++;
51 | const cv = c.value;
52 | });
53 | });
54 |
55 |
56 | bench(() => {
57 | const v = ref(100);
58 | const computeds = [];
59 | for (let i = 0, n = 1000; i < n; i++) {
60 | const c = computed(() => {
61 | return v.value * 2
62 | });
63 | computeds.push(c);
64 | }
65 | let i = 0;
66 | return suite.add("write ref, don't read 1000 computeds (never invoked)", () => {
67 | v.value = i++;
68 | });
69 | })
70 |
71 | bench(() => {
72 | const v = ref(100);
73 | const computeds = [];
74 | for (let i = 0, n = 1000; i < n; i++) {
75 | const c = computed(() => {
76 | return v.value * 2
77 | });
78 | const cv = c.value;
79 | computeds.push(c);
80 | }
81 | let i = 0;
82 | return suite.add("write ref, don't read 1000 computeds (invoked)", () => {
83 | v.value = i++;
84 | });
85 | });
86 |
87 | bench(() => {
88 | const v = ref(100);
89 | const computeds = [];
90 | for (let i = 0, n = 1000; i < n; i++) {
91 | const c = computed(() => {
92 | return v.value * 2
93 | });
94 | const cv = c.value;
95 | computeds.push(c);
96 | }
97 | let i = 0;
98 | return suite.add("write ref, read 1000 computeds", () => {
99 | v.value = i++;
100 | computeds.forEach(c => c.value);
101 | });
102 | });
103 |
104 | bench(() => {
105 | const refs = [];
106 | for (let i = 0, n = 1000; i < n; i++) {
107 | refs.push(ref(i));
108 | }
109 | const c = computed(() => {
110 | let total = 0;
111 | refs.forEach(ref => total += ref.value);
112 | return total;
113 | });
114 | let i = 0;
115 | const n = refs.length;
116 | return suite.add("1000 refs, 1 computed", () => {
117 | refs[i++ % n].value++;
118 | const v = c.value;
119 | });
120 | });
121 |
122 | return suite;
123 | }
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | const queryParams = new URLSearchParams(window.location.search);
2 | const version = queryParams.get("v");
3 | const available = ["ref", "computed", "watch", "watchEffect", "mix", "reactiveObject", "reactiveMap", "reactiveArray"];
4 |
5 | const urlInput = document.getElementById("url");
6 | urlInput.value = version || "3.2.2";
7 |
8 | const benchmarksInput = document.getElementById("benchmarks");
9 | benchmarksInput.value = queryParams.get("b") || available.join(",");
10 |
11 | const abortButton = document.getElementById("abort");
12 | const startButton = document.getElementById("start");
13 | const results = document.getElementById("results");
14 |
15 | const standaloneInput = document.getElementById("standalone");
16 | const iterationsInput = document.getElementById("iterations");
17 |
18 | // This allows aborting and outputting while tests are being run.
19 | Benchmark.options.async = true;
20 |
21 | const maxTime = document.getElementById("maxTime");
22 | maxTime.onchange = function() {
23 | Benchmark.options.maxTime = parseFloat(maxTime.value) || 0;
24 | }
25 |
26 |
27 | function log(...args) {
28 | console.log(...args);
29 | }
30 |
31 | function addBenchmark(name) {
32 | const tr = document.createElement('tr');
33 | tr.innerHTML += ` | `
34 | tr.firstElementChild.innerText = name;
35 | results.appendChild(tr);
36 | }
37 |
38 | function addResult(name, result, fn) {
39 | const tr = document.createElement('tr');
40 | tr.innerHTML += ` | | `
41 | const span = tr.children.item(0).firstElementChild;
42 | span.innerText = name;
43 | span.setAttribute("title", fn.toString());
44 | tr.children.item(1).innerText = result;
45 | results.appendChild(tr);
46 | }
47 |
48 | // @see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
49 | const semverRegex = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
50 |
51 | function getUrl() {
52 | let url = urlInput.value;
53 | if (url.trim() === "") {
54 | alert("Please enter URL");
55 | } else if (semverRegex.test(url)) {
56 | url = `https://cdnjs.cloudflare.com/ajax/libs/vue/${url}/vue.global.js`;
57 | }
58 | return url;
59 | }
60 |
61 | window.start = function() {
62 | const benchmarks = benchmarksInput.value.trim() !== "" ? benchmarksInput.value.split(",") : available;
63 |
64 | document.getElementById("started").style.display = "block";
65 |
66 | let url = getUrl();
67 |
68 | log("Use Vue3: " + url);
69 | log("Benchmarks: " + benchmarks.join(","));
70 | log("Available: " + available.join(","));
71 |
72 | results.innerHTML = `Benchmark (hover to show code) | Result |
`;
73 |
74 | abortButton.removeAttribute("disabled");
75 | startButton.setAttribute("disabled", "disabled");
76 |
77 | injectScript(url).then(() => {
78 | runTests(benchmarks).then(() => {
79 | startButton.removeAttribute("disabled");
80 | abortButton.setAttribute("disabled", "disabled");
81 | alert("All benchmarks finished");
82 | });
83 | });
84 | }
85 |
86 | let suite;
87 | let aborted = false;
88 | window.abort = function() {
89 | startButton.removeAttribute("disabled");
90 | abortButton.setAttribute("disabled", "disabled");
91 |
92 | if (suite) {
93 | suite.abort();
94 | }
95 | aborted = true;
96 | }
97 |
98 | function bench(cb) {
99 | const suite = cb();
100 | const benchmark = suite[suite.length - 1];
101 | benchmark.bench = cb;
102 | }
103 |
104 | async function runTests(benchmarks) {
105 | for (let i = 0, n = benchmarks.length; i < n; i++) {
106 | const name = benchmarks[i];
107 |
108 | window.go = undefined;
109 | await injectScript(`src/${name}.js`);
110 |
111 | suite = go();
112 |
113 | log("Benchmark: " + name);
114 | addBenchmark(name);
115 |
116 | suite.on("cycle", function(event) {
117 | addResult(event.target.name, event.target.toString().substr(event.target.name.length + 3), event.target.bench);
118 | log(String(event.target));
119 | });
120 |
121 | suite.run();
122 |
123 | await new Promise((resolve) => {
124 | suite.on("complete", resolve);
125 | });
126 |
127 | }
128 | }
129 |
130 | window.standalone = function() {
131 | const v = standaloneInput.value;
132 | const index = v.indexOf(":");
133 | if (index === -1) {
134 | alert("Format: {name}:{benchmark}");
135 | } else {
136 | const name = v.substr(0, index).trim();
137 | const bench = v.substr(index + 1).trim();
138 | startStandalone(name, bench);
139 | }
140 | }
141 |
142 | async function startStandalone(name, benchmarkName) {
143 | let url = getUrl();
144 |
145 | log("Use Vue3: " + url);
146 | log("Benchmarks: " + name + ":" + benchmarkName);
147 |
148 | await injectScript(url);
149 |
150 | window.go = undefined;
151 | await injectScript(`src/${name}.js`);
152 |
153 | suite = go();
154 |
155 | let bench;
156 | for (const key in suite) {
157 | if (parseInt(key) >= 0) {
158 | const b = suite[key];
159 | if (b.name === benchmarkName) {
160 | bench = b;
161 | }
162 | }
163 | }
164 |
165 | if (!bench) {
166 | alert("Benchmark not found.");
167 | return;
168 | }
169 |
170 | const iterations = parseInt(iterationsInput.value.replace(/_/g, "")) || 1e4;
171 | log("Iterations: " + iterations);
172 |
173 | const f = bench.fn;
174 | console.profile(benchmarkName);
175 | for (let i = 0; i < iterations; i++) {
176 | f();
177 | }
178 | console.profileEnd(benchmarkName);
179 | }
180 |
181 | function injectScript(src) {
182 | return new Promise((resolve, reject) => {
183 | const script = document.createElement('script');
184 | script.src = src;
185 | script.addEventListener('load', resolve);
186 | script.addEventListener('error', e => reject(e.error));
187 | document.head.appendChild(script);
188 | });
189 | }
190 |
191 |
192 |
--------------------------------------------------------------------------------
/src/mix.js:
--------------------------------------------------------------------------------
1 | function go() {
2 | const { ref, computed, watch, watchEffect } = Vue;
3 |
4 | const suite = new Benchmark.Suite();
5 |
6 | bench(() => {
7 | const v = ref(100);
8 | const c = computed(() => v.value * 2);
9 | const c2 = computed(() => c.value * 2);
10 | const v2 = ref(10);
11 |
12 | const w = watch(c2, (v) => {
13 | v2.value = v;
14 | });
15 |
16 | let ctr = 0;
17 | const we = watchEffect(() => {
18 | const v = c.value + v2.value;
19 | });
20 |
21 | return suite.add("mix of dependent refs, computed, watch and watchEffect", function(deferred) {
22 | v.value += 50;
23 | Vue.nextTick(() => deferred.resolve());
24 | }, { defer: true });
25 | });
26 |
27 | return suite;
28 | }
--------------------------------------------------------------------------------
/src/reactiveArray.js:
--------------------------------------------------------------------------------
1 | function go() {
2 | const { ref, computed, reactive, shallowRef, triggerRef, readonly, toRaw } = Vue;
3 |
4 | const suite = new Benchmark.Suite();
5 |
6 | for (let amount = 10; amount < 1e6; amount *= 10) {
7 | bench(() => {
8 | const rawArray = [];
9 | for (let i = 0, n = amount; i < n; i++) {
10 | rawArray.push(i)
11 | }
12 | const r = reactive(rawArray);
13 | const c = computed(() => {
14 | return r.reduce((v, a) => a + v, 0)
15 | });
16 |
17 | return suite.add(`reduce *reactive* array, ${amount} elements`, () => {
18 | for (let i = 0, n = r.length; i < n; i++) {
19 | r[i]++
20 | }
21 | const value = c.value
22 | });
23 | });
24 |
25 | bench(() => {
26 | const rawArray = [];
27 | for (let i = 0, n = amount; i < n; i++) {
28 | rawArray.push(i)
29 | }
30 | const r = reactive(rawArray);
31 | const c = computed(() => {
32 | return r.reduce((v, a) => a + v, 0)
33 | });
34 |
35 | return suite.add(`reduce *reactive* array, ${amount} elements, only change first value`, () => {
36 | r[0]++
37 | const value = c.value
38 | });
39 | });
40 |
41 | bench(() => {
42 | const rawArray = [];
43 | for (let i = 0, n = amount; i < n; i++) {
44 | rawArray.push(i)
45 | }
46 | const r = reactive({ arr: readonly(rawArray) });
47 | const c = computed(() => {
48 | return r.arr.reduce((v, a) => a + v, 0)
49 | });
50 |
51 | return suite.add(`reduce *readonly* array, ${amount} elements`, () => {
52 | r.arr = r.arr.map(v => v + 1)
53 | const value = c.value
54 | });
55 | });
56 |
57 | bench(() => {
58 | const rawArray = [];
59 | for (let i = 0, n = amount; i < n; i++) {
60 | rawArray.push(i)
61 | }
62 | const r = shallowRef(rawArray);
63 | const c = computed(() => {
64 | return r.value.reduce((v, a) => a + v, 0)
65 | });
66 |
67 | return suite.add(`reduce *raw* array, copied, ${amount} elements`, () => {
68 | r.value = r.value.map(v => v + 1)
69 | const value = c.value
70 | });
71 | });
72 |
73 | bench(() => {
74 | const rawArray = [];
75 | for (let i = 0, n = amount; i < n; i++) {
76 | rawArray.push(i)
77 | }
78 | const r = shallowRef(rawArray);
79 | const c = computed(() => {
80 | return r.value.reduce((v, a) => a + v, 0)
81 | });
82 |
83 | return suite.add(`reduce *raw* array, manually triggered, ${amount} elements`, () => {
84 | for (let i = 0, n = rawArray.length; i < n; i++) {
85 | rawArray[i]++
86 | }
87 | triggerRef(r);
88 | const value = c.value
89 | });
90 | });
91 |
92 | }
93 |
94 | return suite;
95 | }
--------------------------------------------------------------------------------
/src/reactiveMap.js:
--------------------------------------------------------------------------------
1 | function go() {
2 | const { ref, computed, reactive } = Vue;
3 |
4 | const suite = new Benchmark.Suite();
5 |
6 | function createMap(obj) {
7 | const map = new Map();
8 | for (const key in obj) {
9 | if (obj.hasOwnProperty(key)) {
10 | map.set(key, obj[key]);
11 | }
12 | }
13 | return map;
14 | }
15 |
16 | bench(() => {
17 | return suite.add("create reactive map", () => {
18 | const r = reactive(createMap({a: 1}));
19 | });
20 | });
21 |
22 | bench(() => {
23 | let i = 0;
24 | const r = reactive(createMap({a: 1}));
25 | return suite.add("write reactive map property", () => {
26 | r.set("a", i++);
27 | });
28 | });
29 |
30 | bench(() => {
31 | const r = reactive(createMap({a: 1}));
32 | const c = computed(() => {
33 | return r.get("a") * 2
34 | });
35 | let i = 0;
36 | return suite.add("write reactive map, don't read computed (never invoked)", () => {
37 | r.set("a", i++);
38 | });
39 | })
40 |
41 | bench(() => {
42 | const r = reactive(createMap({a: 1}));
43 | const c = computed(() => {
44 | return r.get("a") * 2
45 | });
46 | const cv = c.value;
47 | let i = 0;
48 | return suite.add("write reactive map, don't read computed (invoked)", () => {
49 | r.set("a", i++);
50 | });
51 | })
52 |
53 | bench(() => {
54 | const r = reactive(createMap({a: 1}));
55 | const c = computed(() => {
56 | return r.get("a") * 2
57 | });
58 | let i = 0;
59 | return suite.add("write reactive map, read computed", () => {
60 | r.set("a", i++);
61 | const cv = c.value;
62 | });
63 | });
64 |
65 | bench(() => {
66 | const _m = new Map();
67 | for (let i = 0; i < 10000; i++) {
68 | _m.set(i, i);
69 | }
70 | const r = reactive(_m);
71 | const c = computed(() => {
72 | let total = 0;
73 | r.forEach((value, key) => {
74 | total += value;
75 | });
76 | return total;
77 | });
78 | let i = 0;
79 | return suite.add("write reactive map (10'000 items), read computed", () => {
80 | r.set(5000, r.get(5000) + 1);
81 | const cv = c.value;
82 | });
83 | });
84 |
85 | bench(() => {
86 | const r = reactive(createMap({a: 1}));
87 | const computeds = [];
88 | for (let i = 0, n = 1000; i < n; i++) {
89 | const c = computed(() => {
90 | return r.get("a") * 2
91 | });
92 | computeds.push(c);
93 | }
94 | let i = 0;
95 | return suite.add("write reactive map, don't read 1000 computeds (never invoked)", () => {
96 | r.set("a", i++);
97 | });
98 | })
99 |
100 | bench(() => {
101 | const r = reactive(createMap({a: 1}));
102 | const computeds = [];
103 | for (let i = 0, n = 1000; i < n; i++) {
104 | const c = computed(() => {
105 | return r.get("a") * 2
106 | });
107 | const cv = c.value;
108 | computeds.push(c);
109 | }
110 | let i = 0;
111 | return suite.add("write reactive map, don't read 1000 computeds (invoked)", () => {
112 | r.set("a", i++);
113 | });
114 | });
115 |
116 | bench(() => {
117 | const r = reactive(createMap({a: 1}));
118 | const computeds = [];
119 | for (let i = 0, n = 1000; i < n; i++) {
120 | const c = computed(() => {
121 | return r.get("a") * 2
122 | });
123 | computeds.push(c);
124 | }
125 | let i = 0;
126 | return suite.add("write reactive map, read 1000 computeds", () => {
127 | r.set("a", i++);
128 | computeds.forEach(c => c.value);
129 | });
130 | });
131 |
132 | bench(() => {
133 | const reactives = [];
134 | for (let i = 0, n = 1000; i < n; i++) {
135 | reactives.push(reactive(createMap({a: i})));
136 | }
137 | const c = computed(() => {
138 | let total = 0;
139 | reactives.forEach(r => total += r.get("a"));
140 | return total;
141 | });
142 | let i = 0;
143 | const n = reactives.length;
144 | return suite.add("1000 reactive maps, 1 computed", () => {
145 | reactives[i++ % n].set("a", reactives[i++ % n].get("a") + 1);
146 | const v = c.value;
147 | });
148 | });
149 |
150 | return suite;
151 | }
--------------------------------------------------------------------------------
/src/reactiveObject.js:
--------------------------------------------------------------------------------
1 | function go() {
2 | const { ref, computed, reactive } = Vue;
3 |
4 | const suite = new Benchmark.Suite();
5 |
6 | bench(() => {
7 | return suite.add("create reactive obj", () => {
8 | const r = reactive({a: 1});
9 | });
10 | });
11 |
12 | bench(() => {
13 | let i = 0;
14 | const r = reactive({a: 1});
15 | return suite.add("write reactive obj property", () => {
16 | r.a = i++;
17 | });
18 | });
19 |
20 | bench(() => {
21 | const r = reactive({a: 1});
22 | const c = computed(() => {
23 | return r.a * 2
24 | });
25 | let i = 0;
26 | return suite.add("write reactive obj, don't read computed (never invoked)", () => {
27 | r.a = i++;
28 | });
29 | })
30 |
31 | bench(() => {
32 | const r = reactive({a: 1});
33 | const c = computed(() => {
34 | return r.a * 2
35 | });
36 | const cv = c.value;
37 | let i = 0;
38 | return suite.add("write reactive obj, don't read computed (invoked)", () => {
39 | r.a = i++;
40 | });
41 | })
42 |
43 | bench(() => {
44 | const r = reactive({a: 1});
45 | const c = computed(() => {
46 | return r.a * 2
47 | });
48 | let i = 0;
49 | return suite.add("write reactive obj, read computed", () => {
50 | r.a = i++;
51 | const cv = c.value;
52 | });
53 | });
54 |
55 | bench(() => {
56 | const r = reactive({a: 1});
57 | const computeds = [];
58 | for (let i = 0, n = 1000; i < n; i++) {
59 | const c = computed(() => {
60 | return r.a * 2
61 | });
62 | computeds.push(c);
63 | }
64 | let i = 0;
65 | return suite.add("write reactive obj, don't read 1000 computeds (never invoked)", () => {
66 | r.a = i++;
67 | });
68 | })
69 |
70 | bench(() => {
71 | const r = reactive({a: 1});
72 | const computeds = [];
73 | for (let i = 0, n = 1000; i < n; i++) {
74 | const c = computed(() => {
75 | return r.a * 2
76 | });
77 | const cv = c.value;
78 | computeds.push(c);
79 | }
80 | let i = 0;
81 | return suite.add("write reactive obj, don't read 1000 computeds (invoked)", () => {
82 | r.a = i++;
83 | });
84 | });
85 |
86 | bench(() => {
87 | const r = reactive({a: 1});
88 | const computeds = [];
89 | for (let i = 0, n = 1000; i < n; i++) {
90 | const c = computed(() => {
91 | return r.a * 2
92 | });
93 | computeds.push(c);
94 | }
95 | let i = 0;
96 | return suite.add("write reactive obj, read 1000 computeds", () => {
97 | r.a = i++;
98 | computeds.forEach(c => c.value);
99 | });
100 | });
101 |
102 | bench(() => {
103 | const reactives = [];
104 | for (let i = 0, n = 1000; i < n; i++) {
105 | reactives.push(reactive({a: i}));
106 | }
107 | const c = computed(() => {
108 | let total = 0;
109 | reactives.forEach(r => total += r.a);
110 | return total;
111 | });
112 | let i = 0;
113 | const n = reactives.length;
114 | return suite.add("1000 reactive objs, 1 computed", () => {
115 | reactives[i++ % n].a++;
116 | const v = c.value;
117 | });
118 | });
119 |
120 | return suite;
121 | }
--------------------------------------------------------------------------------
/src/ref.js:
--------------------------------------------------------------------------------
1 | function go() {
2 | const { ref, computed, watch, watchEffect } = Vue;
3 |
4 | const suite = new Benchmark.Suite();
5 |
6 | bench(() => {
7 | const v = ref(100);
8 | return suite.add("create ref", () => {
9 | const v = ref(100);
10 | });
11 | });
12 |
13 | bench(() => {
14 | let i = 0;
15 | const v = ref(100);
16 | return suite.add("write ref", () => {
17 | v.value = i++;
18 | });
19 | })
20 |
21 | bench(() => {
22 | const v = ref(100);
23 | return suite.add("read ref", () => {
24 | const i = v.value;
25 | });
26 | });
27 |
28 | bench(() => {
29 | let i = 0;
30 | const v = ref(100);
31 | return suite.add("write/read ref", () => {
32 | v.value = i++;
33 | const q = v.value;
34 | });
35 | });
36 |
37 | return suite;
38 | }
--------------------------------------------------------------------------------
/src/watch.js:
--------------------------------------------------------------------------------
1 | function go() {
2 | const { ref, computed, watch, watchEffect, } = Vue;
3 |
4 | const suite = new Benchmark.Suite();
5 |
6 | bench(() => {
7 | return suite.add("create watcher", () => {
8 | const v = ref(100);
9 | const w = watch(v, (v) => {
10 | });
11 | });
12 | });
13 |
14 | bench(() => {
15 | let c = 0;
16 | const v = ref(100);
17 | const w = watch(v, (v) => {
18 | });
19 | let i = 0;
20 | return suite.add("update ref to trigger watcher (scheduled but not executed)", () => {
21 | v.value = i++;
22 | });
23 | })
24 |
25 | bench(() => {
26 | let c = 0;
27 | const v = ref(100);
28 | const w = watch(v, (v) => {
29 | });
30 | let i = 0;
31 | return suite.add("update ref to trigger watcher (executed)", function(deferred) {
32 | v.value = i++;
33 | Vue.nextTick(() => deferred.resolve());
34 | }, { defer: true });
35 | })
36 |
37 | return suite;
38 | }
--------------------------------------------------------------------------------
/src/watchEffect.js:
--------------------------------------------------------------------------------
1 | function go() {
2 | const { ref, computed, watch, watchEffect, } = Vue;
3 |
4 | const suite = new Benchmark.Suite();
5 |
6 | bench(() => {
7 | return suite.add("create watchEffect", () => {
8 | const we = watchEffect(() => {
9 | });
10 | });
11 | });
12 |
13 | bench(() => {
14 | let c = 0;
15 | const v = ref(100);
16 | const w = watchEffect(v, (v) => {
17 | const v2 = v.value;
18 | });
19 | let i = 0;
20 | return suite.add("update ref to trigger watchEffect (scheduled but not executed)", () => {
21 | v.value = i++;
22 | });
23 | })
24 |
25 | bench(() => {
26 | let c = 0;
27 | const v = ref(100);
28 | const w = watchEffect(v, (v) => {
29 | const v2 = v.value;
30 | });
31 | let i = 0;
32 | return suite.add("update ref to trigger watchEffect (executed)", function(deferred) {
33 | v.value = i++;
34 | Vue.nextTick(() => deferred.resolve());
35 | }, { defer: true });
36 | })
37 |
38 | return suite;
39 | }
--------------------------------------------------------------------------------