In this paper, starting from vivo Internet technology WeChat public links: mp.weixin.qq.com/s/6gtVR0nVN… Author: Wukong Middle-taiwan R&D Team

【 Wu Space Activities in The Middle Of Taiwan 】

  • “Reveal how Vivo to build tens of millions of DAU activities in the Taiwan – Voyage” mainly for you to tell the vivo activities in the ability and innovation.

  • “Wukong Activity Platform – Micro Component State Management (Part 1)” introduces the state management between RSC components in the activity page and the design ideas behind it.

  • “Wukong Activity Platform – Micro Component State Management (part 2)” explores micro component state management in platform and cross-sandbox environment.

  • “Middle vivo wu empty activities dynamically based on the behavior of default layout plan based on the” full screen “scenario the page layout of thinking as the breakthrough point, based on micro component element unit and provides a new thought of layout plan design, dynamic layout scheme based on behavior presupposition, to share the design details of the purpose and the concrete implementation scheme.

  • Vivo Wukong Activity platform – Micro component multi-terminal exploration is based on the self-service multi-terminal expansion, which means that the multi-terminal micro component selection is richer, the content is more general, the gameplay is more diverse, and the product value will be higher.

The background,

Through the previous wukong activities in the series of articles, we have a certain understanding of micro components, dynamic layout and other technical solutions. In this article, we will take you to understand the performance optimization of Wukong H5.

In the era of mobile Internet, H5 page loading experience is very important. Consumer behavior and attitudes are also significantly affected by page load times, most notably the fact that it is now difficult to wait more than three seconds for a page to load, especially among young people. SOASTA, a company that specializes in performance testing, has concluded that every second of mobile loading can affect conversion rates by up to 20%.

In the process of rapid development of marketing middle Taiwan business, Wukong always put the website response speed and user experience in the first place, through technical innovation, constantly looking for the optimal loading scheme, and achieved good results. Let’s explore.

2. Optimization process

When it comes to performance tuning, front-end ER comes to mind with a classic interview question: What does the browser do from the time the URL is typed to the time the page loads?

The process of experience optimization is the same as this problem, which needs systematic combing and systematic practice. We start from the network, resources, rendering, implementation layer, and continue to explore the loading optimization scheme.

1. Network layer optimization

(1) DNS processing: add DNS-prefetch

The first DNS lookup process for a web site is as follows: Browser cache >> System cache >> Router cache >> ISP DNS cache >> recursive search.

In the mobile environment, the DNS request bandwidth is very small, but the latency is high. To solve this problem, we adopt the prefetch DNS scheme, which can significantly reduce the latency and reduce the average load time by about 1 second.

To help browsers pre-resolve certain domain names, we have added the dnS-prefetch tag to live HTML documents. After the TAB is added, the browser resolves the TAB as follows:

** First step: ** Use meta information to tell the browser that the current page is being preresolved by DNS:

<meta http-equiv="x-dns-prefetch-control" content="on" />
Copy the code

** Use the link tag in the page header to force DNS preresolution:

<link rel="dns-prefetch" href="//topicstatic.vivo.com.cn" />
Copy the code

Wukong needs to generate different DNS-Prefetch addresses according to different regions when launching H5 resources. The added logic for compiling active scaffolding link tag is as follows:

The < %if{%> <link rel="dns-prefetch" href="//topic.vivo.com.cn"> < link rel = "DNS - prefetch" href = "/ / topicstatic.vivo.com.cn" > < %} else if (India) {% > < link rel = "DNS - prefetch" href="//in-goku.vivoglobal.com"> <link rel="dns-prefetch" href="//topicstatic.vivo.com.cn"> <link rel="dns-prefetch" href="//in-gokustatic.vivoglobal.com"> <% } else { %> <link rel="dns-prefetch" href="//asia-goku.vivoglobal.com"> <link rel="dns-prefetch" href="//asia-gokustatic.vivoglobal.com"> <link rel="dns-prefetch" href="//asia-wukongapi.vivoglobal.com"> <% } %>Copy the code

(2) CDN distribution optimization

The full name of the CDN is Content Delivery Network. CDN is an intelligent virtual network built on the basis of the existing network. It relies on the edge servers deployed in various places and through the load balancing, content distribution, scheduling and other functional modules of the central platform, users can obtain the required content nearby, reduce network congestion, and improve user access response speed and hit ratio.

The following figure shows the process of obtaining CDN when terminal users access the page:

Caching is very important for CDN service. Appropriate caching strategy can reduce the request pressure of the source site, so as to improve the page loading speed. Therefore, we need to optimize the static resource storage mode and caching strategy.

The CDN resource cache configuration is as follows:

Wukong uploaded the static resources of H5 topic to CDN, bringing the following improvements:

  • Distributing the static resource files of related libraries to users through CDN can reduce the request pressure on our own servers.

  • Most CTNS have servers around the world, so a server on a CDN may be geographically closer to your users than your own server. Users directly access the edge cache, which greatly improves the response speed of page resources.

  • Not caching HTML entry files, only caching JS, CSS strategy, avoid resources not updated at the same time, accelerate the topic resources to obtain the speed.

The purpose of not caching THE HTML entry file is to prevent the client caching policy from not updating the main entry resource, which leads to the online upgrade failure.

(3) the HTTP / 2

HTTP/2 is defined as:

Hypertext Transfer Protocol Version 2, originally named HTTP 2.0, referred to as H2 (encrypted connections based on TLS/1.2 or above) or H2C (non-encrypted connections) [1], is the second major version of the HTTP protocol used on the World Wide Web.

Breaking HTTP messages into individual frames, interleaving them, and then reassembling them at the other end is one of the most important enhancements to HTTP 2. In fact, this mechanism causes a chain reaction throughout the network technology stack, resulting in a huge performance boost:

HTTP2.0 can be enabled as follows:

server {  
 listen        443**ssl** **http2**; server_name yourdomain; ... ssl on**; ... }Copy the code

Enable HTTP 2 listening:

listen 443 ssl http2;
Copy the code

Multiplexing can replace the original sequence and blocking mechanism, so that multiple resources can be downloaded in a connection in parallel, not limited by the browser’s resource request of the same domain name, and improve the resource loading speed of the whole site.

(4) Dynamic font compression

Font file size is generally about 2M, H5 active page font amount is limited, but only for a small number of special text full introduction of font file, page performance loss is very large. At the same time, due to the complexity and diversity of marketing activities, it is difficult to meet the changing operational needs of simple picture fonts.

It is a technical difficulty for the platform to ensure font size while satisfying font diversity. Finally, we have explored a set of dynamic font compression scheme suitable for the platform.

Font compression, also known as font subset, can be understood as stripping Chinese and English characters from large font files in a specific way and combining them into small font files for page use.

The concept seems a little abstract, but let’s get a sense of what it looks like before and after compression:

Next, we will focus on Wukong’s font compression scheme based on business scenarios. The core demands of compressed fonts are: compressed font files, and text content can be dynamically changed for compression.

Based on the dynamic packaging online method of Wukong Micro components, we choose to use Fontmin to complete dynamic compression of fonts.

Dynamic compression of fonts is divided into the following steps:

** In the first step, ** reads the ID in the specific configuration file, requests the corresponding page interface data in advance, and carries out data collection processing. Some examples of this code:

const request = require('request')
request(url,  (error, response, data) = > {
  if (error) {                  
    console.error(err);
    return
  }
  const res = JSON.parse(data)
  if (res.code === 0) {
    // Get the topic configuration data
    const config = JSON.parse(URLDecode(res.data.config))
    const pages = config.pages
    let str = ' '
    const familyList = new Set()
    pages.forEach(page= > {
      const items = page.items
      items.forEach(item= > {
        // Concatenate the string and font type to be loaded depending on the configuration
        if (item.pluginInfo.enName === 'site-text') {
          str += item.pluginConfig.pureText
          familyList.add(item.pluginConfig.typeFace)
        }
      })
    });
    // Handle the font
    handleFont(str, familyList)
  }
});
Copy the code

** Second step, ** iterates through the font type list familyList, using fontmin to compress the font file. This step requires that we put the font’s local file into the build scaffold beforehand. At the same time, you need to use the WebPack plug-in to generate the corresponding CSS file:

Font dynamic compression processing logic:


const compressFont = (fontText, fontName) = > {
  const srcPath = `dist/${siteId}/font/${fontName}.ttf`; 
  const destPath = `dist/${siteId}/compressFont`;   

  const fontmin = new Fontmin()
    .src(srcPath)               // Enter the configuration
    .use(Fontmin.glyph({        // Extract the font
      text: fontText            // Insert text dynamically
    }))
    .use(Fontmin.ttf2eot())     / / eot transformation
    .use(Fontmin.ttf2woff())    / / woff transformation
    .use(Fontmin.ttf2svg())     / / SVG conversion
    .use(Fontmin.css({
      fontPath: `/compressFont/`.fontFamily: fontName,  
    }))       
    .dest(destPath);            // Output file

  fontmin.run(function (err, files, stream) {
    if (err) {                  
      console.error(err);
      return
    }
    // Read the content of the generated CSS file and synthesize it
    const fontCss = fs.readFileSync(path.join(__dirname, `.. /dist/${siteId}/compressFont/${fontName}.css`)).toString()
    fontStyleStr += fontCss
    loadHtml(fontStyleStr)
  })
}

const handleFont = (fontText, familyList) = > {
  familyList.forEach(name= > {
    compressFont(fontText, name)
  })
}
Copy the code

2. Resource optimization

(1) Lazy image loading

Lazy image loading is a good way to optimize a web page or application. It can automatically obtain more data when the user scrolls the page, and the newly acquired images will not affect the page presentation. At the same time, the images outside the port may never need to be loaded, which can greatly save user traffic and server resources. ‘

The general form of lazy loading is:

  1. Open the home page and slide it

  2. Lazy image loading shows the default image

  3. Replace default image with real image

According to the existing technology stack of Wukong, we choose Vue-Lazyload to support the image of the bit component to load:

  • Native support for Vue, which is available to all components after the platform is extended

  • Easy and quick instruction type development, img tag SRC to v-lazy can achieve lazy image loading

  • As expected, background images can be loaded lazily and image urls can be dynamically changed to WebP

Wukong provides component developers with lazy loading instructions, users do not need to feel the specific loading logic, through the built-in capabilities of Wukong can realize the lazy adding of thematic pictures. The specific usage is as follows:


<template>
  <div>
    <img v-lazy="imgUrl" />
    <div v-lazy:background-image="imgUrl"></div>

    <! -- with customer error and loading -->
    <img v-lazy="imgObj" />
    <div v-lazy:background-image="imgObj"></div>

    <! -- Customer scrollable element -->
    <img v-lazy.container="imgUrl" />
    <div v-lazy:background-image.container="img"></div>

    <! -- srcset -->
    <img
      v-lazy="'img.400px.jpg'"
      data-srcset="img.400px.jpg 400w, img.800px.jpg 800w, img.1200px.jpg 1200w"
    />
    <img
      v-lazy="imgUrl"
      :data-srcset="imgUrl' + '? size=400 400w, ' + imgUrl + ' ? size=800 800w, ' + imgUrl +'/1200.jpg 1200w'"
    />
  </div>
</template>
<script>
export default {
  data() {
    return {
      imgObj: {
        src: 'http://xx.com/logo.png'.error: 'http://xx.com/error.png'.loading: 'http://xx.com/loading-spin.svg',},imgUrl: 'http://xx.com/logo.png'.// String}}},</script>
Copy the code

(2) Image compression

In the mobile environment, image loading has always been a key item that needs to be optimized, so lazy loading is extended to improve user experience.

After the scheme is optimized to the ground, the next step is to consider how to minimize the image volume and improve the image loading efficiency on the premise of guaranteeing the image quality.

WebP is a Google image file format that offers both lossy and lossless (reversible) compression. WebP images have the advantage of being smaller and of higher quality than other compressed images of the same size in different formats.

WebP is a Google image file format that offers both lossy and lossless (reversible) compression. WebP images have the advantage of being smaller and of higher quality than other compressed images of the same size in different formats.

With lossy compression using WebP, we can probably reduce the size of the original image to about a tenth of its original size without major loss of image quality. This is really an amazing efficiency.

We can look at the next set of data to see webP lossy compression:

Webp lossy compression (75% mass ratio)

await execFileSync(cwebp, ['-q'.'75', filePath, '-o', webpPath]);
Copy the code

After the conversion, Wukong will upload the original pictures and converted WebP pictures to the CDN to make a backup capability. In actual business scenarios, you can choose whether to use WebP pictures according to your needs.

The following figure shows Webp before and after compression. The right side shows the compressed image, which has been reduced from 215K to 17K.

Wukong in the use of Webp compression, also encountered a variety of problems, as follows:

  • Why does Wukong choose 75% compression quality?

  • What features of images are not suitable for Webp compression?

  • Some image resources become larger after compression

The following article “Wukong Activity Platform – Efficient Image Loading Scheme Based on Webp” will describe in detail how Wukong provides Webp compression scheme from the perspective of platform.

(3) Cross-domain option requests are avoided

Wukong H5 project adopts a front-end separation scheme. If the server domain name is inconsistent with the topic domain name, it will be affected by the browser same-origin policy.

We find that the data master interface makes two requests, the first of which is a precheck request.

A post request using Application/JSON is bound to include an OPTION request.

Used to get the communication options supported by the destination resource. The OPTIONS method can be used by clients for specific urls or for entire sites (by setting the URL to “*”).

In CORS, you can use the OPTIONS method to initiate a precheck request to see if the actual request can be accepted by the server. The access-control-request-Method header field in the pre-check Request packet tells the server the HTTP Method used for the actual Request. The access-control-Request-headers header field informs the server of the custom header field carried in the actual Request. Based on the information obtained from the precheck request, the server determines whether to accept the actual subsequent request.

The interesting thing is that the topic detail is the GET interface, why do GET requests also initiate option prechecks?

The reason for this starts with simple and complex requests. There are two types of cross-domain requests: simple and complex:

Simple request:

The request mode can be one of the following:

HEAD

GET

POST

The HTTP request header can contain only the following information:

Accept

Accept-Language 

Content-Language 

Last-Event-ID 

Content-type, but can only be one of the following

application/x-www-form-urlencoded 

multipart/form-data 

text/plain

Any request that does not meet the above requirements is considered complex. A complex request contains not only the request that contains the communication content, but also the precheck information.

Topic configuration Interface request header with custom header, the browser will consider the request is not simple, need to send a check to the server to determine whether the domain name allows cross-domain.

After analysis, it is found that the custom header is not required in this business scenario, and it will take at least 100ms to send the pre-check request, which will virtually prolong the page drawing time.

Final solution: Remove the custom header and make it a simple request, avoiding the request being prechecked.

3. Render execution optimization

After the network layer and resource compression optimization are implemented, the next step is to explore the optimization points of browser rendering execution. When it comes to the browser, it must be associated with the page parsing process. The following figure clearly shows how static resources are finally displayed through the browser:

When a DOM element changes and causes the browser to redo the rendering tree, we call this a rearrangement redraw.

What is a rearrangement? When part (or all) of the Render tree needs to be rebuilt due to changes in the element’s size, layout, hiding, etc. This is called reflow. Every page needs to be reflow at least once, when the page first loads.

(1) Avoid rearrangement

Browser structure diagram:

You can see that the browser has a rendering engine that parses and renders the requested content, and which actions will cause the browser to reorder:

(1) Add or delete DOM nodes;

(2) display:none (rearrange and redraw); Visibility :hidden (redraw);

(3) Move the elements in the page;

(4) Change the element size (width, height, inside and outside margin, border, etc.);

(5) The user changes the window size, scrolls the page, etc.;

(6) Initial page rendering;

(7) Change the element content (text or pictures, etc.).

OffsetTop, offsetLeft,... scrollTop, scrollLeft, ... clientTop, clientLeft, ... getComputedStyle() (currentStylein IE)
Copy the code

These attributes need to be given back to the user in real time as geometric or layout attributes, and the browser has to immediately execute the “pending changes” in the render queue, triggering a reorder that returns the correct value.

document.body.style.minWidth = '12OOpx'
document.body.style.overflow = 'hidden'
// Get the offset of a div
document.querySelector('xxx').offsetTop
Copy the code

We optimized the active code execution logic and changed the above direct DOM operations to class-style operations, reducing repeated DOM operations during loading.

(2) Make good use of the Vue life cycle

Making good use of the Vue component life cycle, initializing data in appropriate hooks and manipulating DOM can greatly improve the loading experience.

In the Mounted stage, the browser has completed the RENDER of DOM and CSS rule tree and completed the layout of render tree. At this time, sending data requests will lengthen the request time and render cycle, so it is recommended to execute in beforeCreate. In this way, pre-rendering and request are carried out in parallel.

We put the activity initializing the data action in the beforeCreate phase, and mount the DOM operation and listening in mounted.

{
  beforeCreate(){
    fetch({
      url: topicUrl,
      params: {
        / /...
      }
    }).then(res= >{
      // Data processing
      / /...})},mounted() {
    // global listener
    window.addEventListener('xxx');
    // get dom element by refs
    this.$refs.xxx
    // get dom element use native api
    document.querySelector
  }
}
Copy the code

For the browser, the entire rendering process has not yet started or is ready to start. For Vue, the instance has not yet been initialized, and data Observer and Event /watcher have not yet been called. This is a ripe time to request page initialization data.

(3) Reduce the white screen time

Compared with Native pages, H5 page experience problems are mainly: open a H5 page need to do a series of processing, there will be a period of white screen time, poor experience.

White screen time is the time it takes the browser to start displaying content in response to the user’s input of a web address.

This topic optimization, we use the following ways to reduce the white screen time:

  • Skeleton screen, HTML direct render transition effect

  • Remodel the third party JS introduction sequence

  • Split common code using SplitChunksPlugin;

  • Use dynamic import to split the page code and reduce the JS volume of the first screen

The way to reconstruct the skeleton is a low cost, the effect is very excellent way, the more advanced way is the service end straight out and so on. Due to the quick and clever features of The Wukong activity, the configuration changes need to take effect in real time, so we weighed the advantages and disadvantages of the scheme in the early stage, and adopted the scheme of skeleton and direct rendering of transition effect.

The page directly displays the loading effect after loading HTML. In the bottom version of Android mobile phone, webWiew initialization process will have a high switching process, and the Native titleBar will appear after loading, resulting in the transition effect and the location moving scene.

To solve this problem, we use cSS3 animation to delay the transition effect to avoid conflicts with the WebView initialization.

animation: loading 1s linear 300ms infinite; ... @ keyframes loading {from {
    opacity: 1;
  }
  to {
    opacity: 1; }}Copy the code

This phenomenon can reflect that loading occurs at the same time as webView initialization, and the loading speed is very fast. In order to solve the problem of Loaidng teleportation, we adopt pure CSS3 to realize loading delay without conflict with WebView initialization.

Third, optimization results

1. Comparison of data before and after optimization of the same topic

The following table shows the overall site experience ratings from PageSpeed Insights for the same micro component and configuration activity before and after overall optimization.

2. Effects of domestic activities

Same configuration topic:

3. Effects of overseas activities

Same configuration topic:

4. Performance data collection

1. Common indicators

With regard to indicators, the industry has a large number of programmes and data:

  • Page load time

  • First screen loading duration

  • The Dom Ready time

  • The Dom Complete time

  • Home Page rendering time

  • Home page content rendering time

  • Effective rendering time of home page

  • .

Based on the characteristics of the activity and business common concerns: We collected the page white screen time and first render time, as well as some personalization metrics, in order to measure the activity topic load time and find room for optimization.

2. How to calculate

The loading speed of static resources can be obtained using the Performance Timing API

White screen time:

White screen time = Render start time (first byte time +HTML download complete time) = ResponseStart-navigationStart

First render time = All event registration time = loadEventEnd – navigationStart

Page draw time = Get data until loading ends = loadEventEnd – fetchEnd(self record)

3. Reporting method

For performance data reporting, the platform uses sendBeacon to report non-blocking performance data

The navigator.sendbeacon () method can be used to asynchronously transfer a small amount of data to the Web server over HTTP.

This approach is primarily used to meet the needs of statistical and diagnostic code that typically tries to send data to a Web server before unloading a document.

function stat() {
  navigator.sendBeacon('/path', analyticsData)
}
Copy the code

SendBeacon makes an asynchronous request that is executed as a browser task, disconnected from the current page. Therefore, this method does not block the page loading process or delay page loading.

Fifth, thinking and prospect

At the same time of the above exploration, we are also carrying out project innovation, second open, CSR program exploration, constantly try to improve the H5 experience, the pursuit of excellence.

In my opinion, performance optimization is not a means, but a kind of awareness, developers need to build awareness in the actual development process, in every detail to ensure the user experience.

6. References

  1. Developers.google.com/web/fundame…

  2. 56 ce7 juejin. Im/entry /…