App.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. <script setup>
  2. import { shallowRef, triggerRef } from 'vue'
  3. import { buildData } from './data'
  4. import { defer, wrap } from './profiling'
  5. const selected = shallowRef()
  6. const rows = shallowRef([])
  7. // Bench Add: https://jsbench.me/45lzxprzmu/1
  8. const add = wrap('add', () => {
  9. rows.value.push(...buildData(1000))
  10. triggerRef(rows)
  11. })
  12. const remove = wrap('remove', id => {
  13. rows.value.splice(
  14. rows.value.findIndex(d => d.id === id),
  15. 1,
  16. )
  17. triggerRef(rows)
  18. })
  19. const select = wrap('select', id => {
  20. selected.value = id
  21. })
  22. const run = wrap('run', () => {
  23. rows.value = buildData()
  24. selected.value = undefined
  25. })
  26. const update = wrap('update', () => {
  27. const _rows = rows.value
  28. for (let i = 0, len = _rows.length; i < len; i += 10) {
  29. _rows[i].label.value += ' !!!'
  30. }
  31. })
  32. const runLots = wrap('runLots', () => {
  33. rows.value = buildData(10000)
  34. selected.value = undefined
  35. })
  36. const clear = wrap('clear', () => {
  37. rows.value = []
  38. selected.value = undefined
  39. })
  40. const swapRows = wrap('swap', () => {
  41. const _rows = rows.value
  42. if (_rows.length > 998) {
  43. const d1 = _rows[1]
  44. const d998 = _rows[998]
  45. _rows[1] = d998
  46. _rows[998] = d1
  47. triggerRef(rows)
  48. }
  49. })
  50. async function bench() {
  51. for (let i = 0; i < 30; i++) {
  52. rows.value = []
  53. await runLots()
  54. await defer()
  55. }
  56. }
  57. const globalThis = window
  58. </script>
  59. <template>
  60. <h1>Vue.js (VDOM) Benchmark</h1>
  61. <div style="display: flex; gap: 4px; margin-bottom: 4px">
  62. <label>
  63. <input
  64. type="checkbox"
  65. :value="globalThis.doProfile"
  66. @change="globalThis.doProfile = $event.target.checked"
  67. />
  68. Profiling
  69. </label>
  70. <label>
  71. <input
  72. type="checkbox"
  73. :value="globalThis.reactivity"
  74. @change="globalThis.reactivity = $event.target.checked"
  75. />
  76. Reactivity Cost
  77. </label>
  78. </div>
  79. <div
  80. id="control"
  81. style="display: flex; flex-direction: column; width: fit-content; gap: 6px"
  82. >
  83. <button @click="bench">Benchmark mounting</button>
  84. <button id="run" @click="run">Create 1,000 rows</button>
  85. <button id="runlots" @click="runLots">Create 10,000 rows</button>
  86. <button id="add" @click="add">Append 1,000 rows</button>
  87. <button id="update" @click="update">Update every 10th row</button>
  88. <button id="clear" @click="clear">Clear</button>
  89. <button id="swaprows" @click="swapRows">Swap Rows</button>
  90. </div>
  91. <div id="time"></div>
  92. <table class="table table-hover table-striped test-data">
  93. <tbody>
  94. <tr
  95. v-for="row of rows"
  96. :key="row.id"
  97. :class="selected === row.id ? 'danger' : ''"
  98. >
  99. <td class="col-md-1">{{ row.id }}</td>
  100. <td class="col-md-4">
  101. <a @click="select(row.id)">{{ row.label.value }}</a>
  102. </td>
  103. <td class="col-md-1">
  104. <a @click="remove(row.id)">
  105. <span class="glyphicon glyphicon-remove" aria-hidden="true">x</span>
  106. </a>
  107. </td>
  108. <td class="col-md-6"></td>
  109. </tr>
  110. </tbody>
  111. </table>
  112. <span
  113. class="preloadicon glyphicon glyphicon-remove"
  114. aria-hidden="true"
  115. ></span>
  116. </template>
  117. <style>
  118. .danger {
  119. background-color: red;
  120. }
  121. </style>