Like it and see. Make it a habit

  • How to locate Vue application performance problems
  • Vue application runtime performance optimization recommendations
  • Optimization suggestions for Vue application loading performance

1. How to locate Vue application performance problems

The performance problem of Vue application can be divided into two parts, the first part is runtime performance problem, the second part is load performance problem.

Like other Web applications, the best tool to locate Performance problems of Vue applications is Chrome Devtool. The Performance tool can be used to record runtime Performance problems such as CPU usage, memory usage, and FPS usage for a period of time. The Network tool can be used to analyze the loading performance.

For example, using the Bottom Up TAB of the Performance tool, we can see the most time-consuming operations over a period of time, which is useful for optimizing CPU usage and low FPS. We can see where the most time-consuming operations are occurring. We can know the execution time of specific functions. We can do some specific optimizations.

For details about how to use Chrome Devtool, see Using Chrome Devtool to Locate Performance Problems

2. Suggestions for optimizing the runtime performance of Vue applications

Runtime performance is mainly concerned with CPU, memory, local storage, and timely response to user interaction after Vue application initialization. Here are some useful optimizations:

2.1 Importing Vue files to the production environment

In a development environment, Vue provides many warnings to help you deal with common errors and traps. In a production environment, these warning statements are useless and increase the size of the application. Some warning checks also have minor runtime overhead.

When using build tools like Webpack or Browserify, the Vue source code determines whether to enable production mode based on process.env.node_env, which defaults to development mode. There are methods in both WebPack and Browserify to override this variable to enable Vue’s production mode, and warning statements are removed by the compression tool during the build process.

See Production Deployment for details

2.2 Precompiling templates using single-file components

When using a template in the DOM or a string template in JavaScript, the template is compiled into a rendering function at run time. This is usually fast enough, but it is best avoided in performance-sensitive applications.

The easiest way to precompile a template is to use a single file component — the relevant build Settings take care of the precompilation automatically, so the built code already contains the compiled renderers instead of the original template strings.

See precompiled templates for details

2.3 Extract components from CSS into separate files

When using a single-file component, the CSS within the component is dynamically injected through JavaScript in the form of a

Consult the build tool’s documentation to learn more:

  • webpack + vue-loader (vue-cliThe WebPack template has been pre-configured.
  • Browserify + vueify
  • Rollup + rollup-plugin-vue

2.4 usingObject.freeze()Improve performance

Object.freeze() can freeze an Object. After freezing, you cannot add new attributes to the Object, modify the value of its existing attributes, delete existing attributes, and modify the enumerability, configurability, and writability of existing attributes of the Object. This method returns the frozen object.

When you pass a normal JavaScript Object to the Vue instance’s data option, Vue iterates through all of the Object’s properties and converts them into getters/setters using Object.defineProperty. These getters/setters are invisible to the user, but internally they let Vue track dependencies and notify changes when properties are accessed and modified.

But when Vue encounters an Object property that has been set to unconfigurable, like Object.freeze(), it does not apply data hijacking methods such as setters and getters to the Object. Refer to Vue source code

Vue observer source

2.4.1 Comparison of performance improvement effects

In a VUe-based Big Table benchmark, you can see how to render a 1000 x 10 table with Object.freeze() turned on before and after rerendering.

big table benchmark

Before tuning

After tuning

In this example, using object.freeze () is 4 times faster than not using it

Why 2.4.2Object.freeze()Performance will be better

Do not use the CPU overhead of Object.freeze()

Use the CPU overhead of Object.freeze()

By contrast, using object.freeze () reduces the overhead of the observer.

2.4.3 Object.freeze()Application scenarios

Since object.freeze () freezes objects, it’s a good idea to show classes. If your data attributes need to change, you can replace them with a new object.freeze () Object.

2.5 Flattening the Store data structure

Most of the time, we will find that the interface returns the following deeply nested tree structure of information:

{
  "id": "123"."author": {
    "id": "1"."name": "Paul"
  },
  "title": "My awesome blog post"."comments": [{"id": "324"."commenter": {
        "id": "2"."name": "Nicole"}}}]Copy the code

If direct store this structure in the store, if you want to modify one commenter information, we need to traverse the layers to find the user’s information, and may the user information appeared many times, you also need to put the rest of the user information is modified, each traversal process will bring additional performance overhead.

Assuming that user information is stored in a store structure like Users [ID], the cost of modifying and reading user information becomes very low.

You can manually store the information in the interface as a table of data like this, or you can use some tools, and one of the things I want to mention here is a concept called NORMalize JSON data. Normalizr is an open source tool, The deep-nested JSON object above can be transformed into an object with an ID as the entity representation of the dictionary using a defined schema.

For example, for the JSON data above, we define three schemas for Users Comments Articles:

import {normalize, schema} from 'normalizr';

// Define users Schema
const user = new schema.Entity('users');

// Define comments schema
const comment = new schema.Entity('comments', {
  commenter: user,
});

// Define articles Schema
const article = new schema.Entity('articles', {
  author: user,
  comments: [comment],
});

const normalizedData = normalize(originalData, article);
Copy the code

After normalize, the following data can be stored in a store in this form, and then it becomes very efficient to modify and read the user information of a given ID, reducing the time complexity to O(1).

{
  result: "123".entities: {
    "articles": {
      "123": {
        id: "123".author: "1".title: "My awesome blog post".comments: [ "324"]}},"users": {
      "1": { "id": "1"."name": "Paul" },
      "2": { "id": "2"."name": "Nicole"}},"comments": {
      "324": { id: "324"."commenter": "2"}}}}Copy the code

For more information please refer to normalizr’s documentation at github.com/paularmstro…

2.6 Avoiding performance issues associated with persisting Store data

If you want to make Vue App available offline or need to perform disaster recovery when an interface fails, you may choose to persist Store data. In this case, pay attention to the following aspects:

2.6.1 Performance Problems of Writing Data during Persistence

Vuex-persistedstate, which is popular in Vue community, uses the store subscribe mechanism to subscribe store data mutation. If any mutation occurs, it will be written to storage. The default is localStorage for persistent storage.

This means that by default, every commit will write data to localstorage. Writes to localstorage are synchronous and have a significant performance overhead. If you want to build a 60fps application, you must avoid frequent writes to persistent data

The following is a screenshot captured by the Performance tool in the development environment. It can be seen that there is a delay of 6s:

Six seconds of Caton

Bottom-up: setState takes Up 3241.4ms of CPU execution time, and setState is writing data to the Storage.

Vuex – persistedstate setState source code

We should minimize the frequency of direct writing to Storage:

  • Multiple writes are combined into one operation, such as function throttling or caching data in memory before writing it all together
  • Write only when necessary, such as when data changes in the module you care about

2.6.2 Preventing persistent Storage Capacity From Increasing continuously

Because the capacity of persistent cache is limited, for example, localstorage cache is only 5M in some browsers, we cannot store all data indefinitely, so it is easy to reach the capacity limit, and when the data is too large, read and write operations will increase some performance overhead, and memory will increase.

In particular, normalize flattened API data, scattering one copy of data across different entities, and the next request for new data across other entities, resulting in continued storage growth.

Therefore, when designing a persistent data cache policy, you should also design a cache clearance policy for old data, such as removing old entities one by one when requesting new data.

2.7 Optimize infinite list performance

If your application has very long or infinitely scrolling lists, use windowing techniques to optimize performance by rendering only a few areas of content, reducing the time needed to re-render components and create DOM nodes.

Vue-virtual-scroll list and vue-virtual-Scroller are both open source projects that solve this problem. You can also try implementing a virtual scroll list yourself to optimize performance using DOM recycling, tombstone elements, and scroll anchoring by referring to Google Engineers’ article Acrylates of an Infinite Scroller.

Infinite list design drawn by Google engineers

2.8 Optimizing initial rendering performance of extremely long application content through lazy component loading

Mentioned above list of infinite scene, suit to list elements are very similar, but sometimes, your long list of the Vue applications within the content often is not the same, for example in a complex, in the main interface of the application of the main interface is composed of so many different modules, and only the first screen users see one or two modules. Modules in invisible areas are also executed and rendered during initial rendering, incurs some additional performance overhead.

With component lazy loading you only need to render a skeleton screen when not visible, without actually rendering the component

You can lazily load components directly, and not load and initialize components in invisible areas to avoid the overhead of initializing the render runtime. For details, see the component lazy loading introduction to learn how to achieve component granularity lazy loading.

3. Optimize Vue application loading performance

3.1 Optimize loading performance using SSR and Prerender

In a single page application, there is usually only one HTML file, and then the routing script is matched according to the URL visited, and the page content is dynamically rendered. The biggest problem with single-page apps is that the first screen takes too long to view.

Single-page applications make multiple requests to display a page, fetching HTML resources for the first time, retrieving data through the request, and rendering the data to the page. Moreover, due to the existence of microservices architectures, it is possible to render a web page with multiple data requests, resulting in RTT (round-trip delay) for each data request, resulting in a long time to load the page.

Comparison of server-side rendering, pre-rendering, and client-side rendering

In this case, SSR and Prerender can be used to improve load performance. With these two schemes, users can directly read the content of the web page, save a lot of RTT (round-trip delay), and inline some resources on the page to further improve load performance.

Server rendering (SSR) can be set up step by step using Nuxt or following the Vue SSR guide provided by Vue official.

3.2 Optimizing the loading performance of Long Application content through lazy component loading

In the case of the super-long application mentioned above, the lazy loading of components can optimize the performance of the initial render, and in fact, it can be helpful to optimize the performance of the application load.

The lazy loading of component granularity combined with asynchronous components and Webpack code sharding can ensure the loading of components on demand, as well as component-dependent resources, interface requests, etc. Compared with lazy loading of pictures, it can further load resources on demand.

Use component lazy load prior to request waterfall diagram

Use component lazy load after request waterfall diagram

Using the component lazy loading scheme is very helpful for initial rendering of extremely long content applications, reducing the number of required resource requests and shortening the rendering critical path

conclusion

This article summarizes some performance optimization measures for Vue applications at runtime and load time. Here is a review and summary:

Vue application runtime performance optimization measures

  • Import Vue files into the production environment
  • Precompile templates using single-file components
  • Extract components from CSS into separate files
  • usingObject.freeze()Improve performance
  • Flattening the Store data structure
  • Use persistent Store data wisely
  • Component lazy loading

Vue application load performance optimization measures

  • Server render/prerender
  • Component lazy loading

Reference Documents:

  • Chrome Devtool guide
  • Vue source
  • Production Environment Deployment
  • normalizr

Pay attention to the public account, learn together: