Before we think about improving page rendering speed, what determines the speed of a page? Obviously, there are two main influencing factors.

  1. Resource transfer time (TCP connection time and response time)
  2. Dom rendering time

The elapsed time of these two aspects can be calculated by using the window built-in object Window. performance in the browser environment

Performance // Computing resource transmission time const tcpTimes = (timing. ConnectEnd - timing. ConnectStart)/1000 // DomTimes = (timing. Domcomplete-timing. DomLoading)/1000Copy the code

Common front-end optimizations

So the way to do front-end optimization is usually to optimize around two aspects, namely to minimize resource transfer time and DOM rendering time. Here are three common front-end optimizations:

  1. Server optimization
  2. Reduced transmission volume – compression and slicing techniques
  3. Use caching wisely

In terms of expansion, each optimization method can correspond to multiple specific behaviors. Mature solutions are provided for server optimization, VUE and React ecosystem. Examples include Vue’s nuxt.js and React’s next.js.

For the second method, the following methods can be adopted to achieve optimization by reducing the transmission volume:

  • Resource compression (including images, font libraries, and JS scripts)
  • Tree Shaking: Remove useless code
  • Code separation and extraction of common code
  • Lazy loading
  • Use webP format images
  • Close the Source Map in production
  • .

For the third way, that is, through the rational use of caching to achieve the purpose of performance optimization, this is the focus of this article.

What are the caching methods

  1. Cookies – Cache, not secure
  2. Global state cache – not persistent and takes up memory
  3. The local cache – locaStorage sessionStroage, persistent

For local caches, we need to know the difference between locaStorage and sessionStroage:

  • LocaStorage, which will always exist unless you manually delete it,
  • SessionStroage: a session-level caching policy. The page session is closed and cleared.

Create a cache architecture

Here we implement a caching architecture based on request sending. Some issues to consider when using caching for performance tuning are:

  • The amount of cache caused by pressure, stored pressure.
  • Update of cache – how to keep data up to date after it has been updated.

With these two considerations in mind, as little change as possible is desirable when caching data.

To solve the cross domain

1. Webpack agent forwarding: 3. Jsonp, suitable for static pages and jquery– not suitable for VUE. 4. Back-end interface configuration cross-domain resource Sharing (CORS)– simple and efficient

Cache idea: After the first load, there is no need to request hot items to be placed in localStroage, and unpopular items to be placed in status cache

// Cache object creation should use the singleton pattern -- there can only be one cache object globally. if(! window.mycache){ window.mycache = function(){ window.cache = {}; window.cachArr = []; return function(){ get:function(api){ return new Promise((resolve, reject) => { if(cache[api]){ resolve(cache[api]) }else{ if(localStroage.getItem(api)){ resolve(JSON.parse(localStroage.getItem(api))); }else { this.set(api).then(res=>{ var name = ''; if(res.data.ishot){ if(cacheArr[1].length>4){ name=cacheArr[1].shift(); localStroage.removeItem(name) } localStroage.setItem(api, Json.stringify(res)); cacheArr[1].push(api) }else { if(cacheArr[0].length>3){ name = cahceArr[0].shift(); delete cache[name]; } cache[api] = res; cacheArr[0].push(api); } resolve(res); }) } } }) }, set:function(api){ return axios.get(api); }, remove:function(api){ delete cache(api); }}}}Copy the code

This code is designed to a large number of conditional statements. To sum up, cache entries can be divided into three categories:

  1. The cache
  2. localStroage
  3. Send the request and handle the caching logic

We can use the strategy pattern optimization of the process, the strategy pattern is to separate the use of the algorithm and algorithm implementation of open, different algorithms or behaviors are encapsulated in various strategies in the class, the Context will ask delegated to these policy object, the policy object can be carried according to the request to return different results, it can show the polymorphism of objects. The realization of policy pattern is not complicated. The key is how to find the value of encapsulating the ideas of change, delegation and polymorphism behind the realization of policy pattern.

if(! window.mycache){ window.mycache = function(){ window.cache = {}; window.cacheArr = []; return { get:function ( api ) { var state = 0; var stateHandler = [ function(resolve,reject) { resolve(cache[api]);  }, function(resolve,reject) { resolve(JSON.parse(localStorage.getItem(api)));  }, function(resolve,reject) { this.set(api).then((res) => { var type = 0; var name = cacheArr[type].shift();  if(res.data.ishot){ type == 1; name = cacheArr[type].shift(); if(cacheArr[1].length>4){ localStorage.removeItem(name);  } localStorage.setItem(api,JSON.stringify(res)); } else { if(cacheArr[0].length>3){ delete cache[name];  } cache[api] = res; } cacheArr[type].push(api); resolve(res);  }) } ] return new Promise((resolve,reject)=>{ if(localStorage.getItem(api)){ state = 1; } if(! cache[api] && ! localStorage.getItem(api)){ state = 2; } stateHandler[state].call(this, resolve, reject); }) }, set:function(api){ return axios.get(api); }, remove:function(api){ delete cache(api); }}}}Copy the code

Based on this, we have completed the implementation of a cache architecture, which can now be directly introduced and used in the project. Create a. Vue file

<template>
...
</template>
<script>
export default {
    date() {
        return {
            goodInfo: {}
        }
    },
    mounted: function(){
        mycahce.get('/api/'+this.$route.params.goodApi).then(res=>{
            this.goodsInfo = res.data
        })
    }
}
</script>
Copy the code

If there is an API value in localStroage or global state cache, fetch it directly. If not, send axios request and cache the corresponding data content.

In the above discussion, we noticed that while using cache to improve performance, we also need to consider the storage pressure caused by the amount of cache. In the code, we set the maximum amount of cache, when this amount is exceeded, we need to delete old data and store new data, thus controlling the maximum amount of data that can be cached. As for the second consideration, the update of cache, how to ensure that the cache is consistent with the actual resources and at the same time improve the cache hit ratio. If you are using static resource caching, the best way to do this is with hash values. However, there is no good solution to the API request interface cache based on the improvements in this article. However, there are still several ways to achieve the purpose of cache update:

  1. You can set the cache duration and the actions that trigger the deletion: logging out, manually triggering the cache deletion. This approach costs less and is suitable for many front-end application scenarios, such as menu information and personal information interface data can use this caching strategy.
  2. Websocket, the cost is relatively high, need to start a websocket service later, can achieve more immediate data update.
var ws = new Websocket(); ws.onmessage=(data)=> { if(data.api){ mycache.remove(api); }}Copy the code
  1. Small request: When entering a project, make a small request and the response will only send you back the changed interface. The key design is that the amount of data transferred is small, and the interface needs to pass in the time node of the current data capture. The interface takes this time node and compares the current data to see if it is updated. If so, it returns the updated data API.