How performant is Vue 3's provision/injection?
P粉946336138
P粉946336138 2023-08-26 09:46:02
0
1
553
<p>I work on a project that relies on application-level <code>provide</code> for global state management. At first, the <code>provide</code>d object was small, but it grew as the project grew. </p> <p>How much impact will it have on application performance by injecting this object where the data is needed? Without implementing a global state management tool like Pinia, is it worth breaking the large objects we provide into separate objects to provide "chunks" of data where needed? </p>
P粉946336138
P粉946336138

reply all(1)
P粉854119263

I've done some basic benchmarking and was wondering if frequently used variables should be provided/injected, or if they should be accessed from the Pinia store in a large number of components.

The results show that there is no significant performance difference.

My first test case is very basic: Providing/injecting a single bool is not the same as getting it from the Pinia storage in the component and rendering the component multiple times. 50k components took between 20-24 seconds to render, also using provide/inject and using Pinia. There's no consistent difference to say either one is faster/slower.

In the second test, I used a larger object, an array of about 1MiB of data (measured in a JSON print without spaces). The difference is also not significant. I've rendered 50k components and both using injection and storage access took about the same amount of time, between 19-26 seconds.

The components in each case render the boolean value of the theme variable, so their rendering time does not increase with large data vs. small boolean values.

After all, I've come to the conclusion that there really isn't any meaningful difference between provide/inject and the Pinia store. The only obvious difference is that performance is less stable with larger data and more predictable with smaller data. No matter how many times I repeat the test on the boolean values, the time is always between 20-24 seconds and as the data increases I get some outliers like 19 seconds or 26 seconds. Again nothing consistent, this could just be a fluctuation in my actual CPU usage and nothing to do with Provide/inject vs. Pinia store usage.

I tested on Chrome v110 (x86_64) on macOS using vue@3.2.47 and pinia@2.0.32.

Test code I used:

<template>
  <div>Inject {{ number }}: {{ injected ? 'yes' : 'no' }}</div>
</template>
<script setup lang="ts">
  export interface Props {
    number?: number,
  }
  const props = withDefaults( defineProps<Props>(), {
    number: 0,
  })
  import { inject } from 'vue'
  const injected = inject('inject-test')
</script>
<template>
  <div>Store get {{ number }}: {{ testStore.test ? 'yes' : 'no' }}</div>
</template>
<script setup lang="ts">
  export interface Props {
    number?: number,
  }
  const props = withDefaults( defineProps<Props>(), {
    number: 0,
  })
  import { useTestStore } from 'stores/test'
  const testStore = useTestStore()
</script>
<template>
  <div v-if="testStore">
    <h1>Store get</h1>
    <pre>Start: {{ start() }}</pre>
    <div class="test">
      <StoreGet v-for="n in 50000"
                :key="n"
                :number="n"
      />
    </div>
    <pre>End: {{ end() }}</pre>
    <pre>Duration: {{ endTime - startTime }} seconds</pre>
  </div>
  <div v-else>
    <h1>Inject</h1>
    <pre>Start: {{ start() }}</pre>
    <div class="test">
      <Inject v-for="n in 50000"
              :key="n"
              :number="n"
      />
    </div>
    <pre>End: {{ end() }}</pre>
    <pre>Duration: {{ endTime - startTime }} seconds</pre>
  </div>
</template>

<script setup lang="ts">
  import { provide } from 'vue'
  import Inject from './test/Inject.vue'
  import StoreGet from './test/StoreGet.vue'

  // Roughly 1M of json data
  import { large } from '@sbnc/datasets/largeTest'

  // Comment one or the other:
  const testData = true
  //const testData = large

  // Choose which one to test:
  const testStore = true // set false to test inject

  provide( 'inject-test', testData)

  import { useTestStore } from 'stores/test'
  const testStore = useTestStore()
  testStore.test = testData

  let startTime
  let endTime

  function start() {
    startTime = performance.now()
    return startTime
  }
  function end() {
    endTime = performance.now()
    return endTime
  }
</script>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template