| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- <script setup lang="ts" vapor>
- import {
- ref,
- shallowRef,
- triggerRef,
- watch,
- type ShallowRef,
- type WatchSource,
- } from '@vue/vapor'
- import { buildData } from './data'
- import { defer, wrap } from './profiling'
- const isVapor = !!import.meta.env.IS_VAPOR
- const selected = ref<number>()
- const rows = shallowRef<
- {
- id: number
- label: ShallowRef<string>
- }[]
- >([])
- // Bench Add: https://jsbench.me/45lzxprzmu/1
- const add = wrap('add', () => {
- rows.value.push(...buildData(1000))
- triggerRef(rows)
- })
- const remove = wrap('remove', (id: number) => {
- rows.value.splice(
- rows.value.findIndex(d => d.id === id),
- 1,
- )
- triggerRef(rows)
- })
- const select = wrap('select', (id: number) => {
- selected.value = id
- })
- const run = wrap('run', () => {
- rows.value = buildData()
- selected.value = undefined
- })
- const update = wrap('update', () => {
- const _rows = rows.value
- for (let i = 0, len = _rows.length; i < len; i += 10) {
- _rows[i].label.value += ' !!!'
- }
- })
- const runLots = wrap('runLots', () => {
- rows.value = buildData(10000)
- selected.value = undefined
- })
- const clear = wrap('clear', () => {
- rows.value = []
- selected.value = undefined
- })
- const swapRows = wrap('swap', () => {
- const _rows = rows.value
- if (_rows.length > 998) {
- const d1 = _rows[1]
- const d998 = _rows[998]
- _rows[1] = d998
- _rows[998] = d1
- triggerRef(rows)
- }
- })
- async function bench() {
- for (let i = 0; i < 30; i++) {
- rows.value = []
- await defer()
- await runLots()
- }
- }
- // Reduce the complexity of `selected` from O(n) to O(1).
- function createSelector(source: WatchSource) {
- const cache: Record<keyof any, ShallowRef<boolean>> = {}
- watch(source, (val, old) => {
- if (old != undefined) cache[old]!.value = false
- if (val != undefined) cache[val]!.value = true
- })
- return (id: keyof any) => (cache[id] ??= shallowRef(false)).value
- }
- const isSelected = createSelector(selected)
- </script>
- <template>
- <h1>Vue.js ({{ isVapor ? 'Vapor' : 'Virtual DOM' }}) Benchmark</h1>
- <div
- id="control"
- style="display: flex; flex-direction: column; width: fit-content; gap: 6px"
- >
- <button @click="bench">Benchmark mounting</button>
- <button id="run" @click="run">Create 1,000 rows</button>
- <button id="runLots" @click="runLots">Create 10,000 rows</button>
- <button id="add" @click="add">Append 1,000 rows</button>
- <button id="update" @click="update">Update every 10th row</button>
- <button id="clear" @click="clear">Clear</button>
- <button id="swaprows" @click="swapRows">Swap Rows</button>
- </div>
- <div id="time"></div>
- <table>
- <tbody>
- <tr
- v-for="row of rows"
- :key="row.id"
- :class="{ danger: isSelected(row.id) }"
- v-memo="[row.label, row.id === selected]"
- >
- <td>{{ row.id }}</td>
- <td>
- <a @click="select(row.id)">{{ row.label.value }}</a>
- </td>
- <td>
- <button @click="remove(row.id)">x</button>
- </td>
- <td class="col-md-6"></td>
- </tr>
- </tbody>
- </table>
- </template>
- <style>
- .danger {
- background-color: red;
- }
- </style>
|