preface

The introduction

Take a look at these three questions over and over again.

  • Have different people asked you: What is front-end performance optimization?
  • Have different interviewers asked you: What do you do for front-end performance optimization?
  • Have you ever asked yourself: What should I say when someone asks me about front-end performance optimization?
  • Do you have your own set of answers about performance optimization that can be discussed by technology professionals and nodded by whites?

If you do, where is your answer.

Let’s start with one thing: how does a front-end project go from idea to ground

For example, the whole Tmall home page. There are a variety of answers, you see if there is one you think of.

  • Create-react-app initializes a project. Write some components on the home page, such as tofu block, Header, Bar, long ScrollView. The project then compiles, packages and goes online.

  • Webpack hands a project.

    • Routes are loaded on demand and can be browsed without trace with high performance ScrollList with loadmore.

    • Because it is the home page, it will obviously involve the first screen loading problem. Let’s arrange the skeleton screen.

    • Another set of Best practices for WebPack is to end up with as small a package as possible.

    • Let’s have a set of SSR. Because the DOM structure of the home page is too complex, if you go Virtual DOM, it will be too slow to wait until the GPU rendering UI.

Did any of the above hit you at any point? Makes sense or not, is that what you’re thinking? Does it always feel like something is missing?

This article does not cover the rest. But this is where you have to say something, make an impression.

  • System layer design
    • 20% of a new system is reserved for existing business. The remaining 80% is for system evolution. Can think about, tmall home has been changing, but still can ensure that performance standards.
  • Business layer design
    • Whether the existing services are coupled with other services, whether there are front-end services, and if so, where are the permissions of the front-end services? Can existing services be continuously compatible with new services based on system evolution?
  • Application layer design
    • Such as micro front end, such as component library, such asnpm install
    • Webpack optimization
    • Skeleton screen
    • Routes are dynamically loaded on demand
  • Code layer design
    • Write high-performance React code? How to take advantage of Vue3 Time Slices?
    • Don’t say. So the primarywasteJust build up slowly.

So, you should have figured out what’s missing from “always feeling like something’s missing.” Yes, front-end performance optimization is not only the optimization of application layer and code layer, but also the optimization of system layer and business layer.

Read the above psychological preset, then enter the formal theme.

Performance optimization process

Try this process:

  • Performance indicator setting (FPS, page seconds open rate, error rate, number of requests, etc.)

    • How do you let your boss know about your optimization plan? Let’s say your boss is not technical.
    • Tell your boss the white screen time has been reduced by 0.4s.
    • Tell the boss, weak net case home seconds open.
    • Tell your boss that the server is under a lot of pressure due to the high volume of HTTP requests, and now there are no more than 5 requests per page to the server for resources.
    • Tell the boss…
  • Determination of performance criteria

    • Identify what indicators are needed
  • Benefits evaluation

    • Program to your boss’s satisfaction. / Facepalm. PNG (manual dog head)
  • Diagnosis of listing

    • The list will give you the data for each indicator.
  • Optimization means

    • Hybrid APP performance optimization

      • Optimization scheme during App startup
      • Page white screen stage optimization scheme
      • Optimization of the first screen rendering stage
    • First comment seconds open X methods?

      • Lazy loading
      • The cache
      • Available offline
        • Ensure that the first load is second open offline package design
      • parallelization
    • Skeleton screen

      • Component skeleton screen
      • Picture skeleton screen
    • NSR

    • SSR

    • WebView layer and code architecture layer optimization

      • WebView performance optimization
      • Parallel initialization
      • Resource preloading
      • Data interface request optimization
      • Front-end architecture performance tuning
        • Long list performance optimization
        • Packaging optimization
  • Performance of the project

    • If you’re sure, go get it.
  • Performance practices

    • Get ready to get your pages out fast in all kinds of harsh environments!

summary

Now, do you have a complete understanding of front-end performance optimization? Many times when talking about performance tuning you first need to talk about how to “diagnose” performance. Most of the time, though, you won’t be asked how you monitor performance. (Her voice drops off…)

Let’s talk more about optimization

The first screen seconds open a variety of optimization means

1. The lazy loading

One of the most common optimization methods.

Lazy loading is when the critical content is loaded first and the non-critical content is loaded lazily during a long page loading process. For example, when we open a page, its content exceeds the size of the browser’s viewport, we can first load the front end of the viewport content, the rest of the content and so on it into the viewport after loading on demand.

Take chestnuts. Tmall home page selection. The picture above.

It happens to be the Tmall 618 event. This IOS version of tmall home page selection. If you often visit tmall home page selection, you will find that it has almost achieved a non-trace browsing. Lazy loading works well here, but it’s not just lazy loading.

That said lazy loading, tmall home page selection did what? Can you guess.

  1. Lazy loading
    • Lazy image loading
      • Picture isnativeI’ve done caching.
      • Load only when it appears in the visible area
    • Card preloading (lazy loading timing changed)
      • You don’t load the card by entering the viewable area. Instead, it preloads the next card when the last one comes into view. Because it’s much faster to load the card UI than the image. This is also one of the guarantees of non-trace browsing.
    • Animation lazy loading
      • If you scroll fast enough,ListThe scrolling height changes a lot, and the requested data will eventually be outstripped by your high scrolling speed. In other words, you can’t see the next card until new data is available, so you have to wait. That’s when you have oneloadingAnd then when you get the new data, the new card will appear and automatically slide fully into the viewable area.
      • Someone here is going to say,IOSDamping is supposed to make the animation and scrolling smoother. What I want to say here is,AndroidThat’s fine, too.

2. The cache

If lazy loading is essentially the ability to request non-critical content after the first screen is provided, caching is the ability to grant a second access without requiring a repeat request. Interface caching and static resource caching play a key role in first-screen optimization.

Going back to lazy loading, why do you have to swipe for a while before you get to a point where there’s no new data? The reason is that the cache has run out of data, so the server can only give the latest data.

  • Interface cache The implementation of the interface cache, if it is in the end, all requests go through the Native request, so as to achieve the interface cache. Why do you do that?

    There are two forms of page presentation in App, page presentation developed by Native and page presentation developed by H5. If Native is used to make requests uniformly, there is no need to request the data interface that has already been requested. If you use H5 to request data, you must wait until the WebView is initialized to request data (i.e., serial request), while in the case of Native request, you can start to request data before the WebView is initialized (i.e., parallel request), which can effectively save time.

    So, how do you cache interfaces through Native? We can do this with SDK encapsulation, which modifies the original data interface request method to implement an AXIos-like request method. Specifically, encapsulate the INTERFACE that includes POST, Get, and Request functionality into the SDK.

    In this way, when the client makes a request, the application will call the SDk-AXIos method, and the WebView will intercept the request and check whether the App has a local data cache. If so, it will use the interface cache. If not, it will first request the data interface from the server, obtain the interface data and store it in the App cache.

  • Static resource cache first look at the diagram.

91 requests, 113 kB transferred, 2.2MB resources,Finish: 2.93s,DOMContentLoaded: 177 Ms. 2.2m Look at the Size column and you should be on to something.

That’s right. HTTP cache. Data interface requests are generally few, only a few, while static resources (such as JS, CSS, images, fonts, etc.) are too many. Take tmall home page as an example, 91 requests except a few script, the rest are static resource requests.

So, how do you do a static caching scheme? There are two cases, one is that static resources do not need to be modified for a long time, and the other is that static resources are modified frequently. Try refreshing the page a few more times.

If the resource doesn’t change much over a long period of time, say for a year, we can use a strong Cache, such as cache-control. Specifically, you can set cache-Control :max-age=31536000 to allow the browser to directly use the local Cache file for a year instead of making requests to the server.

In the second case, if the resource itself changes at any time, you can set the Etag to implement the negotiated cache. Specifically, on the first request for a resource, set the Etag (such as using the MD5 of the resource as the Etag) and return a status code of 200, followed by a request with an if-none-match field to ask the server If the current version is available. If the server does not change the data, it returns a status code of 304 to the client, telling the client not to request the data, but to use the cached data directly. Of course, there’s some webView-related stuff here, but I won’t go into it…

3. Offline processing

Offline refers to the scheme in which the online resource data that changes in real time is statically transferred to the local file when accessing it.

Offline packages are one way to go offline, and it’s a way to store static resources locally to your App, and I won’t go into details here.

But there’s another, more complex, offline solution: statically localizing page content. The offline mode applies to the scenario where the login page is not required, such as the home page or list page, and supports the SEO function.

So how do you go offline? The page is pre-rendered when the build is packaged, and by the time the front-end request falls on index.html, the content is already rendered. At this point, you can implement pre-rendering with Webpack’s prerender-SPA-plugin to take it offline.

The following is an example of code for pre-rendering in Webpack:

// webpack.conf.js
var path = require('path')
var PrerenderSpaPlugin = require('prerender-spa-plugin')
module.exports = {
  // ...
  plugins: [
    new PrerenderSpaPlugin(
      // The path where the compiled HTML needs to be stored
      path.join(__dirname, '.. /dist'),
      // Lists which routes need to be pre-rendered
      [ '/'.'/about'.'/contact'])]}// When the interview offline can talk about this, often is to do a dead spot, but the risk is proportional to the benefit, it is worth the risk. That is, do you have your own pre-render scheme?
Copy the code

4. The parallelization

If lazy loading, caching, and offline are all about the request itself, trying to reduce or delay the request, parallelization is about optimizing the request channel, solving the request blocking problem, and thus reducing the first screen time.

For example, the queue for vaccination in Guangzhou was reported on the news how it was blocked. That, in addition to allowing people to stagger their vaccinations, could also increase the number of doctors who get them. We can also increase the number of request channels when dealing with request blocking — with the help of HTTP 2.0 multiplexing solutions.

In the HTTP 1.1 era, there were two performance bottlenecks, serial file transfers and a limit of six connections to domain names. In the AGE of HTTP 2.0, because of the multiplexing capabilities provided, data was no longer transmitted in text (text must be transmitted sequentially, otherwise the receiver would not know the order of the characters), but in binary data frames and streams.

A frame is the smallest unit of data to be received, and a stream is a virtual channel in a connection that can carry two-way information. Each stream has a unique integer ID to identify the order of the data, so that the receiver can merge the data according to the order after receiving the data without any error in the order. So, in the case of flows, no matter how many resource requests there are, just one connection can be established.

After the file transfer problem is solved, how to solve the problem of connection limit with the domain name? The Nginx server, for example, was originally limited to six connections per domain name, and the maximum number of concurrent requests was 100. With THE adoption of HTTP 2.0, the maximum number of concurrent requests is now 600, a six-fold increase.

You have to ask, isn’t that what the operations side does? What do we need to do on the front end? We want to change the static file merge (JS, CSS, image files) and static resource server do domain name hash these two development methods.

Specifically, with HTTP 2.0 multiplexing, individual files can go online separately, and there is no need to merge JS files. Here is a reservation question, have you used the Ali Antd component library? The library is not completely updated each time it is updated. It may update only a Button component this time and only a Card component again. How is it possible for individual components to be distributed separately?

To resolve static domain name blocking (which is a performance bottleneck), static domain names need to be divided into PIC0-PIC5 to improve request parallelization. Static resource domain name hashing solves the problem, but the DNS resolution takes much longer and requires additional servers. HTTP 2.0 multiplexing solves this problem.

To be continued

The next part will introduce the specific practice plan. Dry goods have more content.

I never tell anyone about front-end performance optimization (part 2)

How the advanced/experienced front end answers JavaScript interview questions (1)