preface

This article is a continuation of how I package components for performance optimization based on the business needs of the company.

Take a look at the table below:

Last time I shared how I packaged a multi-functional table component in a tree structure based on the business of the company, as a whole, to meet the early requirements. But as the business expands, the test comes with satisfying users in terms of performance.

Next, I’m going to take a note of what I think about performance 📝 to share ~

Feel good small partner that point to me 👍, is the biggest support for me. Hee hee ~

If there is a better plan, add V to discuss ~

Thinking analysis optimizes what

Users make fun of the view’s slow rendering. As the amount of data increases, the speed at which the interface returns the data slows down, which in turn slows down the page rendering. Now we need to think about how to improve the rendering speed from the front end to make the page appear to the user faster.

I’ll start with the elements rendered on the page. To make the first load faster, I used lazy loading to load images.

Again, because it’s a tree structure, I designed a recursive component. However, as the amount of data increases, the pain point of slow rendering of recursive components is also exposed. So solving the rendering problem of recursive components will speed up the first load.

What is the solution to optimize

Based on the above analysis, INSTEAD of loading images directly with the IMG tag, I wrote a lazy loading component PMLazyImg through the third-party library Lozad to load images.

A general idea for implementing lazy loading components

  • The installation
npm install --save lozad
Copy the code
  • inPMLazyImguse

Add a ref attribute to lazy elements & By adding a data-src attribute to elements, the data-src attribute value fixedSrc is the true SRC path

<img :data-src="fixedSrc" @click="evt => $emit('click', evt)" alt ref="img" />
Copy the code

Instantiation lozad

lazyObj.value= lozad();
lazyObj.value.observe();
Copy the code

Listen for SRC incoming from the outside and assign the data-src attribute to the SRC attribute of the element

img.value.dataset['loaded'] = false;
lazyObj.value.triggerLoad(img.value);
Copy the code

Here the lazy loading component is basically done.

This time I also did the cell code refactoring, I pulled the contents of the cell into a component, so that outsiders can design their favorite cell content only through configuration. So how do you design cells through configuration?

Here I use TS syntax for cell configuration rules. And each cell forms a table-column configuration rule. Support: type: cell type, name: table header name, width: cell width, height: cell height, etc. The specific code is as follows:

/*** Cell type */
export enum eleType {TEXT}
/*** Operation type */
exportenum ActionsType { DEL} interface BtnsType { label? :String; props? :Object;
    type: ActionsType;
    handler: (. args: any) = > void; formatter? :(val? : any, row? : any) = > void; isHide? :(val? : any, row? : any) = > void; } type BtnsTypeOptions = BtnsType[]; type BtnsConfig = BtnsTypeOptions; interface DropDownType { label? :String; props? :Object;
    menu: BtnsConfig;
}
export interface CellTypes {
    type: eleType;
    name: string;
    prop: string | null; width? : number; height? : number; formatter? :(val: any, row: any) = > void; btns? : BtnsConfig; dropdown? : DropDownType; handler? :(. args: any) = > void;
}
export type ColumnOptions = CellTypes[];
Copy the code

So the next time a new cell content requirement changes, you just need to change the configuration and customize the new cell content.

As for how to solve the pain point of recursive component rendering, I optimized it in the following way:

How will descendant nodes be rendered

  • On the template I passv-ifTo control theChild nodeswithSun nodeWhether to show it so it doesn’t load the first time you render itChild nodesandSun nodeI’m only going to render in certain situations, like when I expand.

Struct with unloaded child elements vs struct with loaded child elements:

This will also speed up the first load. (Previously controlled by using V-show)

How does the parent node render

  • I useIntersectionObserverThis API does lazy loading of nodes, which affects rendering of recursive components.

Here’s a key question to consider: How do you determine the relationship between the list of data and the visible region?

I have bound each node with an ID attribute on the template, so in the IntersectionObserver callback function I can put the visible target elements into a renderList array I maintain. Furthermore, the renderList array can be used to match each node in a recursive component template with the id attribute of the node data item. Finally, the unobserve element has to stop being observed.

On the table layout, I also did some reconstruction. You need to add height and overflow: Auto attributes to tBody. This is basically the rendering of the level 1 node.

Part of the template code is as follows:

That is, the view layer invisible element is not loaded when it is first loaded

Invisible node vs visible node:

Node reuse

Instead of using an index, each cell and row of data is associated with the ID of each node by setting the key attribute.

Compare the results before and after optimization

Performance diagram before and after optimization:

Compare the data before and after

  • Total render time: 9336ms vs 4331ms.

  • LCP: Time :5330.8ms vs 2296.5ms.

Note: LCP Largest Contentful Paint is a user-centric performance metric that tests the user’s perception of page loading speed because it records the point in time when the main content of the page might have finished loading. A quick LCP that gives users a sense of the usability of the page.

  • FCP: 2957.6 ms vs 2296.5ms

Note: FCP stands for First Contentful Paint. As the name suggests, it represents the First time a browser paints content to the screen.

Think about the aftermath & feelings

The above optimization is based on the Angle of the front end, in fact, can also be optimized through the lazy loading of the interface. (data does not need to be returned in full, first returns the level 1 element, and then calls the level 2 or level 3 interface when needed) of course, there are better ways to optimize!!

This code refactoring was not just a technical optimization, but I also had some other ideas about the technology.

Most developers complain about frequent requirements changes and code refactoring. (Why not design the product first 😭)

In my opinion, the business cannot be a constant layer and will change with the market changes. Developers should embrace change and actively refactor code!!

May change the state of mind may be less complaining more happy ~ why not?