Which is better for Vue3 and Vue2 responsiveness?

There are pitfalls everywhere in the interview questions, making it hard to guard against. If you don’t check the interview questions in advance, you will most likely be asked by the interviewer with a boring face.

The interviewer asked: Which is better in responsive performance between Vue3 and Vue2?

I thought to myself: This interviewer doesn’t play cards according to the routine, shouldn’t he ask “the difference between Vue3 responsiveness”, “what problem does Vue2 responsiveness solve” and so on? Suddenly asked about performance, is this still a question? Of course, Vue3 responsive performance is better. Is Vue upgraded in the direction of poor performance?

Me: Vue3 Responsive performance is better

The interviewer smiled slightly (falling into the pit) and asked: Why?

Me: Vue3 adopts ES6 Proxy for responsiveness, which is supported by mainstream browsers now, and the performance supported by browsers is better than that achieved by JavaScript code! And the Proxy does not need to iterate over the properties of the object to add the response.

Interviewer: Proxy has advantages in this area, but everything has two sides, and there are also advantages and disadvantages. Vue2 has been polished and optimized for so many years, and there is already a set of optimal performance solutions to deal with and weaken Object.defineProperty( ) The impact of the shortcomings. The Proxy of Vue3 came out not long ago. In terms of the shortcomings of Proxy, Vue3 still needs long-term polishing and tuning. The responsive performance of Vue3 may not be better than that of Vue2.

me! And this angle?

So this interview was hung up. . . . .

Responsive performance is divided into two parts: responsive initialization performance and responsive view update performance.

Responsive initialization

Vue2 responsive initialization

<div id="app"></div>
<script>
  const len = 1;
  const arr = Array(len);
  for (let i = 0; i < len; i ++ ) {<!-- -->
    arr[i] = {<!-- --> id: i, name: "test" };
  }
  console.time("Vue2 init");
  new Vue({<!-- -->
    el: "#app",
    data() {<!-- -->
      return {<!-- -->
        arr,
      };
    },
    created() {<!-- -->
      console.timeEnd("Vue2 init");
    },
  });
</script>

When the array length is 1, the initialization time is: 1ms, and the memory usage is: 1.5MB

Array Length Initialization Time Memory
1 1ms 1.5MB
1000 6ms 2.4MB
100000 162ms 57MB
1000000 1443ms 569MB

It can be seen from the table that as the length of the array increases, the initialization time and memory usage increase in detail.

Vue3 responsive initialization

const {<!-- --> createApp } = Vue;

const len = 1;
const arr = new Array(len);
for (let i = 0; i < len; i ++ ) {<!-- -->
  arr[i] = {<!-- --> id: i, name: "test" };
}

console.time("Vue3 init");
createApp({<!-- -->
  data() {<!-- -->
    return {<!-- -->
      arr,
    };
  },
  created() {<!-- -->
    console.timeEnd("Vue3 init");
  },
}).mount("#app");

performance:

Array Length Initialization Time Memory
1 4ms 1.2MB
1000 3ms 2.5MB
100000 4ms 6.8MB
1000000 4ms 25MB

There is almost no change in the initialization time when the array length is increased, and the memory usage is much less than that of Vue2.

Summary

The responsiveness created by Object.defineProperty() used by Vue2 requires each item in the variable array, and adds get and set methods to create Observer and dep instances, so memory and initialization time skyrocket as the length of the array increases.

Vue3 uses Proxy to implement responsiveness, does not traverse the array, and only creates a Dep instance when the object property is read. When the property value is an object, the object is then responsive to achieve lazy responsiveness. Therefore, there are not many instances created, so initialization The time is almost constant as the length of the array increases, and the memory does not increase much. The performance of Vue3 is higher than that of Vue2 on the responsive initialization of large amounts of data.

Responsive View Update

Vue2 responsive view update

<div id="app">
  <div>{<!-- -->{ arr. length }}</div>
  <button @click="onClick">click</button>
</div>

<script>
  const len = 1000000;
  const arr = Array(len);
  for (let i = 0; i < len; i ++ ) {<!-- -->
    arr[i] = {<!-- --> id: 0, name: "test" };
  }
  console.time("Vue2 init");
  new Vue({<!-- -->
    el: "#app",
    data() {<!-- -->
      return {<!-- -->
        arr,
      };
    },
    updated() {<!-- -->
      console.timeEnd("Vue2 update");
    },
    methods: {<!-- -->
      onClick() {<!-- -->
        console.time("Vue2 update");
        for (let i = 0; i < 50; i ++ ) this. arr. unshift({<!-- --> a: 1 });
      },
    },
  });
</script>

performance:

array length update time
1 1ms
1000 4ms
100000 304ms
1000000 3293ms

Vue3 responsive view update

<div id="app">
  <div>{<!-- -->{ arr. length }}</div>
  <button @click="onClick">click</button>
</div>

<script>
  const {<!-- --> createApp } = Vue;

  const len = 1;
  const arr = new Array(len);
  for (let i = 0; i < len; i ++ ) {<!-- -->
    arr[i] = {<!-- --> id: i, name: "test" };
  }

  createApp({<!-- -->
    data() {<!-- -->
      return {<!-- -->
        arr,
      };
    },
    updated() {<!-- -->
      console.timeEnd("Vue3 update");
    },
    methods: {<!-- -->
      onClick() {<!-- -->
        console.time("Vue3 update");
        for (let i = 0; i < 50; i ++ ) this. arr. unshift({<!-- --> id: i, name: "test" });
      },
    },
  }).mount("#app");
</script>

performance:

array length update time
1 5ms
1000 75ms
100000 6708ms
1000000 70980ms

Summary

Vue3’s unshift operation updates extremely slowly under large amounts of data, and the reason for this slowness is the unshift operation. We are trying to see how the push operation performs:

<div id="app">
  <div>{<!-- -->{ arr. length }}</div>
  <button @click="onClick">click</button>
</div>

<script>
  const {<!-- --> createApp } = Vue;

  const len = 1;
  const arr = new Array(len);
  for (let i = 0; i < len; i ++ ) {<!-- -->
    arr[i] = {<!-- --> id: i, name: "test" };
  }

  createApp({<!-- -->
    data() {<!-- -->
      return {<!-- -->
        arr,
      };
    },
    updated() {<!-- -->
      console.timeEnd("Vue3 update");
    },
    methods: {<!-- -->
      onClick() {<!-- -->
        console.time("Vue3 update");
        for (let i = 0; i < 50; i ++ ) this. arr. push({<!-- --> id: i, name: "test" });
      },
    },
  }).mount("#app");
</script>

performance:

array length update time
1 2ms
1000 1ms
100000 2ms
1000000 4ms

It can be seen that the push operation of Vue3 is very fast, but the unshift operation is very slow, because the unshift operation changes the index of the elements in the array, and all array items must be reassigned to the index + 1, which is the overhead of 50*array length. In the same way, the same performance problem occurs when deleting the front item of the array.

How to solve the performance problem of unshift operation:

1. Merge multiple unshifts into one unshift

<div id="app">
  <div>{<!-- -->{ arr. length }}</div>
  <button @click="onClick">click</button>
</div>

<script>
  const { createApp } = Vue;

  const len = 1000000;
  const arr = new Array(len);
  for (let i = 0; i < len; i ++ ) {
    arr[i] = { id: i, name: "test" };
  }

  createApp({
    data() {
      return {
        arr,
      };
    },
    updated() {
      console.timeEnd("Vue3 update");
    },
    methods: {
      onClick() {
        console.time("Vue3 update");
        const list=[]
        for (let i = 0; i < 50; i ++ ) list. push({ a: 1 });
        this.arr.unshift(...list)
      },
    },
  }).mount("#app");

performance:

array length update time
1 1ms
1000 5ms
100000 164ms
1000000 1828ms

The update time is much faster after unshift is merged into one operation, but there will definitely be multiple delete and unshift operations in actual projects.

2. The array does not respond in depth

<div id="app">
  <div>{<!-- -->{ arr. length }}</div>
  <button @click="onClick">click</button>
</div>

<script>
  const {<!-- --> createApp, markRaw } = Vue;

  const len = 1000000;
  const arr = new Array(len);
  for (let i = 0; i < len; i ++ ) {<!-- -->
    arr[i] = {<!-- --> id: i, name: "test" };
  }

  createApp({<!-- -->
    data() {<!-- -->
      return {<!-- -->
        arr: markRaw(arr),
      };
    },
    updated() {<!-- -->
      console.timeEnd("Vue3 update");
    },
    methods: {<!-- -->
      onClick() {<!-- -->
        console.time("Vue3 update");
        for (let i = 0; i < 50; i ++ ) this. arr. unshift({<!-- --> a: 1 });
        this.arr = markRaw([...this.arr]);
      },
    },
  }).mount("#app");
</script>

performance:

array length update time
1 1.2ms
1000 2ms
100000 7ms
1000000 45ms

This method updates faster, but this method is only applicable to list display, and changes must be reassigned.

Summary

The responsive performance of Vue3 is not completely better than that of Vue2, and the responsive processing of arrays should be optimized according to the specific situation.