Website performance optimization throughout the development of each stage, involving knowledge is relatively scattered, how to sort out the scattered knowledge, coherent, in my mind there is a map, in the actual combat, according to the map of the optimization point each break, this needs to build their own knowledge system.

An interview question

A classic interview question: What happens from entering a URL in the browser’s address bar to rendering the page?

In brief, there are mainly the following processes:

1. Check whether cached resources exist. If so, return the resource directly to the browser renderer (step 5), otherwise enter the network request process. 2. Obtain the IP address of the server that requests the domain name. 3. Establish a TCP connection with the server based on the IP address. 4. The server sends an HTTP request, processes the request, and returns an HTTP response. 5. The browser takes the response data, parses it, and renders it.Copy the code

Below, we will introduce the optimization points of the above stages, and gradually form the knowledge system of performance optimization. On the whole, the above process is mainly divided into network and rendering these two chunks. Among them, the network optimization focuses on reducing network requests, reducing the volume of resources and optimizing the loading of resources on the first screen. The optimization of the rendering process mainly includes JS execution optimization, page layout and redrawing optimization, CSS computing style optimization and so on. Learning this knowledge can not only help us improve the performance of the site, but also deepen our understanding of the front-end development process.

Due to the long space, we will divide into two articles, this one is about the optimization of the network process, and the next one will talk about the optimization of the rendering process.

Here is a mind map for Web chapter.

Reduce network requests

Network requests are relatively time-consuming. Reducing network requests can speed up page loading and improve website performance and user experience.

Browser cache

Take a hole. I’ll write more about it later.

The local store

localStorage

LocalStorage is a new localStorage API of html5. The storage capacity supported by common browsers is 5M. It is only saved in the browser and does not participate in the communication with the server.

Data stored in localStorage has no expiration date and can only be deleted manually. Because the data is stored in the browser’s local hardware device, even if the browser is closed, this part of the data still exists, the next time you open the browser to visit the website data can continue to use.

LocalStorage is very simple to use, commonly used API includes setItem, getItem, removeItem, clear four methods.

// Add or set the data item localstorage. setItem("username", GetItem ('username') // Remove the data item with the specified key name from localStorage Localstorage.removeitem ('username') // Clear all data in localStorage.clear()Copy the code

It is worth noting that localStorage cannot cross domains and can only be read and written under the same source. Parse will restore the data type of an object or array using json. stringify.

sessioStorage

SessioStorage and localStorage use the same API. They differ in their data persistence. The data stored in the sessioStorage is available only for the current session. The data will be deleted when the session is terminated by closing the TAB.

Application scenarios

Compared with sessioStorage, localStorage is more widely used. Because of the persistence of data in localStorage, it can be used to store some daily needs of websites and stable resources.

For example, Taobao’s localStorage stores a lot of Base64 image strings (small ICONS on the front screen).

You can also use it to keep a search history, like digging gold.

You can also save local Settings for your site, such as day/night mode for reading the site, font size, background color, and so on.

File merging

File merge and split

Merging files reduces HTTP requests and is easy to implement with build tools such as Webpack, which by default bundles all dependent modules into a bundle.js.

One thing to note here is that if the merged file is large and takes a long time to load, the first screen rendering delay will be very long; On the other hand, there is the problem of cache invalidation. In the actual project, we will add hash to the JS file name to mark whether the file is updated or not. If the file is merged into a single file, a small change in the source file will cause the hash change of the entire file and the cache will also become invalid. So file merge needs to consider a reasonable strategy, in fact, file split strategy. In addition, file splitting can also take advantage of parallel downloads of the same domain name.

Building with WebPack packs all dependent modules into a SINGLE JS file by default, which can be split with the help of various plug-ins. For example, using the mini-CSs-extract-plugin to separate CSS into separate files:

const MiniCssExtractPlugin = require('mini-css-extract-plugin') module:{ rules:[ { test: /\.css$/, use: [MiniCssExtractPlugin. Loader, 'CSS - loader'] / / don't use the style - loader, For MiniCssExtractPlugin loader},]}, plugins: [new MiniCssExtractPlugin ({filename: 'style/index.css' // default dist main.css})]Copy the code

Separate third-party libraries, the base libraries in business code, common operations are:

  1. Externals
  2. SplitChunks
  3. DllPlugin

Sprite figure

Sprite image splices several small ICONS into a large image. Sprite image can reduce HTTP requests and speed up web page display in http1.x environment.

The size of the Sprite icon should be small. Large images are not recommended to be spliced into Sprite images. It should also be a static icon on the site, not an icon retrieved dynamically through an Ajax request. Therefore, it is usually used as a website logo, icon and other pictures.

When building with WebPack, you can use PostCSS-Sprites to automatically compose Sprite images. Specific steps:

First, configure postCSs-loader in webpack.base.js:

//webpack.base.js module.exports = { module: { rules: [ { test: /\.css$/, use: ['vue style-loader','css-loader', 'postCSs-loader '] // Configure postCSs-loader}, {test: /\. Less $/, use: ['vue style-loader',' CSs-loader ',' postCSs-loader ',' less-loader'] // Configure postCSs-loader}]}};Copy the code

Then create.postcsrc. Js in the project root directory and configure postCSs-sprites.

module.exports = { "plugins": [require('postcss-sprites')({// all static images used in CSS will be merged by default // Use filterBy to specify images to be merged, such as here, where only images under icon folder filterBy will be merged: function (image) { if (image.url.indexOf('/images/icon/') > -1) { return Promise.resolve(); } return Promise.reject(); } }})]Copy the code

The default is to merge the image into a Sprite image called sprite.png. Postcss-sprites composite Sprite image

Base64

Base64 is not an image format, but an encoding method that converts any binary into a text string. When we use Base64 to encode an image, we convert the binary data of the image into a string.

data:image/png; base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAAAXNSR0IArs4c6QAA...Copy the code

By using the Base64 encoding directly as the SRC attribute value of the tag, the browser automatically parses the Base64 encoding and does not make another image request.

Each HTTP request takes a certain amount of time to set up. For various small ICONS that are frequently used on websites, the time to set up HTTP requests may be longer than the time to download the image itself. In this case, Base64 encoded small graphs can be used to reduce HTTP requests.

Due to the principle of Base64 encoding, Base64 encoding is about 3/4 larger than the original image. If large images are encoded in HTML/CSS, the volume of the latter will increase significantly and the opening speed of web pages will be significantly affected. Therefore, Base64 encoding transformations are generally recommended for small graphs only.

The urL-loader in Webpack can automatically decide whether to Base64 encoding based on the file size:

{ test: /\.(png|jpe? G | GIF) $/ I use: [{loader: 'url - loader, the options: {limit: 8192 / / less than 8 m images can be converted into Base64},},],},Copy the code

Reduce resource volume

In addition to reducing network requests, reducing resource volume was another important optimization point that was essential to our development process.

Build tool optimization

Using build tools to merge and compress resources is the most common operation in engineering practice. Nowadays the most mainstream building tool is undoubtedly Webpack, we also mainly discuss the optimization of resource volume using Webpack.

Specific operations can refer to the last article to solve the webAPCK construction optimization strategy, in the face of webAPCK construction analysis tools, speed optimization, volume optimization, are combined with examples to explain, here is no longer repeated.

Choose the right image format

If possible, use CSS effects (gradients, shadows, rounded corners, etc.) instead of images.

When you have to use image resources, it is important to choose the right image format because different image formats have different sizes for the same visual effect.

  • JPG: lossy compression, smaller volume. Suitable for large image with rich color, such as background image, rotation image, Banner image, etc.

  • PNG: lossless compression, large volume, transparency support. Suitable for small Logo, simple color and strong contrast images, etc.

  • Webp: 2010 launched by Google, the use of better image data compression algorithm, image volume is smaller, and has the naked eye recognition of no difference in image quality; Both lossless and lossy compression modes, transparency support and animation features are available. But in terms of compatibility, Internet Explorer and Safari are not supported.

  • SVG: Vector graphics, images can be infinitely large without distortion, small size. Applicable to all kinds of icon, logo.

Optimized resource loading on the first screen

For contents other than the first screen, if all the contents are loaded at one time, the rendering speed of the first screen will be affected. Also, if the page is long, even if the entire page loads, the user won’t necessarily scroll through the entire content.

Therefore, a very important optimization point is, when opening a website, try to load only the resources contained in the first screen content, and resources outside the first screen, and so on when you need to load. This makes the first screen of the page render faster.

Lazy loading

Route lazy loading

In a single-page application, if all the components are packaged together, the JS package can become very large, affecting the speed of the page when it is first loaded. With route lazy loading, we can split the components of different routes into different code blocks and load the corresponding components only when the route is accessed.

With dynamic import, lazy loading of routes is easy. For details, see the dynamic import section in the previous article.

Lazy loading of images

The SRC attribute is not assigned directly to the SRC attribute. Instead, the SRC URL is assigned to the image when the enters the viewable area.

For each tag that needs lazy loading, set a data-src attribute that stores the image URL. When the element enters the visible area, the data-src value is retrieved and assigned to the SRC attribute.

So how do you tell if is in viewable area? Use getBoundingClientRect to get the top distance between the top of the element and the top of the browser viewport. Use window.innerHeight to get the viewport height viewHeight. Indicates that the element is in viewable area.

Let’s implement a simple lazy load.

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta Name ="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> width: 200px; background-color: #eee; } </style> </head> <body> <div> <img class="lazy" Data - SRC = "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3176859023, & FM = 26 & gp = 0. 1719957347 JPG" > < / div > < div > <img class="lazy" Data - SRC = "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2413205756, & FM = 26 & gp = 0. 2857128339 JPG" > < / div > < div > <img class="lazy" Data - SRC = "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2356708534, & FM = 26 & gp = 0. 2525790159 JPG" > < / div > < div > <img class="lazy" Data - SRC = "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1332858679, & FM = 26 & gp = 0. 869019665 JPG" > < / div > < div > <img class="lazy" Data - SRC = "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2450079006, & FM = 26 & gp = 0. 3171044776 JPG" > < / div > < div > <img class="lazy" Data - SRC = "https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1181825476, & FM = 26 & gp = 0. 2174805292 JPG" > < / div > < / body > < script > const imgs = document. QuerySelectorAll (' lazy ') / / need lazy loading image tag const viewHeight = window. The innerHeight / / Let num = 0 function lazyload(){for(let I =num; i<imgs.length; I ++) {let distance = viewHeight - imgs[I].getBoundingClientRect(). Top If (distance >= 0){// Get the image URL stored in the data-src attribute, SRC = imgs[I]. SRC = imgs[I]. GetAttribute ('data-src') Num = I +1}}} lazyLoad () {window.addeventListener ('scroll', lazyload, // Listen for scroll events </script> </ HTML >Copy the code

The final result is shown below:

Server side rendering

Vue, React and other frameworks make development simple and efficient, but also increase the amount of resources that need to be loaded on the page. In addition to the business code, the page can only be rendered after the framework code is loaded. For the first screen rendering speed of the site with high requirements, you can consider server-side rendering. Not only does it speed up the first screen, it also helps SEO. The practice of server-side rendering is often closely combined with the front-end framework (such as Vue, React, etc.). For more implementation principles and details, you can refer to the article written by the author to understand the Vue SSR principle and build the project framework.

Basic network optimization

DNS

DNS translates domain names into IP addresses. The optimization of DNS mainly includes the following two points:

  1. Reduce DNS queries.

DNS query results are cached locally on the client. Therefore, the client obtains the CORRESPONDING IP address from the DNS server for the first time and obtains the IP address from the local SERVER for the next time. Therefore, static resources are not scattered across multiple domain names, which reduces the need for DNS queries through the DNS server.

  1. Preload.

When browsing a web page, the browser resolves the domain name of the web page in the background when loading the web page. In this way, DNS resolution is no longer required when accessing the connection on the current web page.

You can control the pre-resolution of all connections in the current page, or the pre-resolution of specific connections, configured in the head TAB:

<meta http-equiv="x-dns-prefetch-control" content="on">Copy the code
<link rel="dns-prefetch" href="//baidu.com">Copy the code

CDN

CDN is used to store static resources such as JS, CSS and images. Static resources have the characteristics of high access frequency and large flow. CDN is an important means to speed up static resources. CDN brings these performance optimizations

This concludes the performance optimization summary for the network part, and the next article will be devoted to performance optimization for the rendering part. See you next time

The resources

Front-end performance optimization principles and practices

Working principle and practice of browser