Common methods of front-end optimization

  1. Reduce http requests
    Avoid multiple requests for small resources. You can combine multiple resources into one resource, such as js, because sending network requests is time-consuming
  2. css is placed at the head and js is placed at the bottom of the body
    It helps to render the page faster. css will block the execution of js, because js will be executed only after cssom is created, and js will block the whole rendering process
    However, js can also be placed in the header, but to avoid blocking rendering, you can add the defer or async attribute
  3. Use font icon instead of picture Icon
    Font icons are much smaller than picture icons, saving transmission overhead
  4. Reduce redraw rearrangement
    Avoid using js to frequently manipulate styles. You can use class substitution
    Multiple dom operations can be added to or displayed with the help of documentFragment or elements of display:none
    Using transform and opacity to implement animation can reduce redrawing and rearrangement, which are attributes handled separately from compositor.
  5. When judging that there are many statements, avoid using if else. You can use switch case or strategist mode, which is easy to read and maintain
  6. Avoid animating with timers
    The timer animation needs to specify the time, and the improper control of the time will cause the page animation to jam.
    You can use requestAnimationFrame to animate. We have also introduced this api to execute logic for frames
  7. Static resources can be placed on CDNs
    cdn is a group of servers distributed in various regions, so it can serve users according to which server and which server users recently use
  8. You can use web workers
    For long-time logic, you can use web workers to start additional threads to execute, which will not block the execution of js code of the main thread.
    be careful:
    • Homology restriction
    • Without a window object, its global object or this is itself
    • Unable to access the dom node
    • Data is transferred with the main thread by copying
      Simple use
// Main thread
var worker = new Worker('worker.js') // URI of the work thread
worker.postMessage([10, 24])
worker.onmessage = function(e) {
    console.log(e.data)
}

// Worker thread, worker js
onmessage = function (e) {
    if (e.data.length > 1) {
        postMessage(e.data[1] - e.data[0])
    }
}
// Stopping the worker thread can call the instance in the main thread close method
worker.terminate()
// Or the worker calls its own close()
this.close()
  1. Event related

    1. Event delegation
      Binding the same event to multiple child elements is not as good as directly binding the event to the parent element. The memory overhead of binding events can be saved by means of event delegation

    2. Anti shake
      When an event is triggered frequently, such as form input check, the check will be performed only after a short period of time after the input is stopped or suspended, instead of always checking
      Note that this needs to be bound

      function debounce(callback, delay) {
        let timer = null
        return function(){
        // Here, you need to clear the last timer. It is always triggered and cleared. Only when the trigger stops can the timer be bound for execution
          clearTimeout(timer)
          let context = this
          timer = setTimeOut(()=> {
            callback.call(context)
          })
        }
      }
      
    3. throttle
      Anti shake is only for operations that are triggered frequently and will pause and stop. If some operations are triggered all the time and need to respond when they do not stop, for example, when judging the mouse rolling distance to realize lazy loading, throttling can be used for mouse rolling
      Implementation mode
      timer
      When the timer is timed, it will end before the time when it is triggered, that is, the timer still exists. Otherwise, the logic will be executed and the timer will be cleared for re timing next time.

      	/*
      	  If the timer still exists, exit and do not execute. If it does not exist, bind a timer
      	  The bound function will be executed after the delay time arrives. After execution, you need to set timer = null
      	  Note that the timer is not cleared and is set to null because the timer saves the id value of the timer
      	  The timer is cleared, but the id value is still
      	*/
      	function throttle(callback){
      	  let timer = null
      	  return function(){
      	    if(timer) return
      	    let context = this
      	    timer = setTimeout(() => {
      	      callback.call(context)
      	      timer = null
      	    })
      	  }
      	}
      	```
      	
      

    time stamp
    The time stamp method does not need to use a timer to judge whether the difference between the current time and the last execution time is > the reference value. If it is greater than the reference value, execute and set the reference value as the current time, otherwise it ends.

    function throttle(callback, delay){
      let pre = 0
      return function(){
        let now = Date.now()
        if(now - pre > delay) {
          callback.call(this)
          pre = now
        }
      }
    }
    			
    			
    
  2. Lazy loading of pictures
    First, give the picture a resource occupancy attribute and wait until the picture appears in the viewport before loading. Otherwise, loading all pictures at the same time will consume a lot of network resources.
    There are two main ways to implement lazy loading. One is to judge whether to reach the viewport by using the style attribute of the element, and the other is to use the api encapsulated by js.
    Implementation of clientHeight, offsetTop and scrollTop
    Principle:
    clientHeight is the height of the container viewport, and scrollTop is the height of the scroll bar. The sum of the two is the actual distance from the element to the top of the container viewport if it is not in the scroll bar, while offscttop is the offset distance from the element to the parent node. If clientHeight + scrollTop ≤ offscttop, it means that the element appears in the viewport and can be displayed.
    Note: use an n to save the position of the currently loaded picture, so that you don't have to cycle through it from the beginning every time

    	<style>
    	  #div{
    	    border: 2px solid black;
    	    height: 500px;
    	    overflow: auto;
    	  }
    	  .div {
    	    margin-bottom: 5px;
    	    background-color: aquamarine;
    	    width: 200px;
    	    height: 300px;
    	  }
    	</style>
    	<body>
    	  <ul id="list">
    	    <li><img data-src="./images/iu.jpg"  src='./images/lazy.png' alt=""></li>
    	    <li><img data-src="./images/iu1.jpg" src='./images/lazy.png' alt=""></li>
    	    <li><img data-src="./images/iu2.png" src='./images/lazy.png' alt=""></li>
    	    <li><img data-src="./images/iu3.jpg" src='./images/lazy.png' alt=""></li>
    	    <li><img data-src="./images/iu4.jpg" src='./images/lazy.png' alt=""></li>
    	    <li><img data-src="./images/iu5.jpg" src='./images/lazy.png' alt=""></li>
    	    <li><img data-src="./images/iu6.jpg" src='./images/lazy.png' alt=""></li>
    	    <li><img data-src="./images/iu7.jpg" src='./images/lazy.png' alt=""></li>
    	    <li><img data-src="./images/iu8.jpg" src='./images/lazy.png' alt=""></li>
    	    <li><img data-src="./images/iu9.jpg" src='./images/lazy.png' alt=""></li>
    	    <li><img data-src="./images/iu10.jpg" src='./images/lazy.png' alt=""></li>
    	    <li><img data-src="./images/zzf_01.jpg" src='./images/lazy.png' alt=""></li>
    	  </ul>
    	</body>
    
    	
    	let list = document.getElementById('list')
    	let imgs = document.getElementsByTagName('img')
    	let len = imgs.length
    	let n = 0
    	function lazyLoad(){
    	  let clientHeight = list.clientHeight
    	  let scrollTop = list.scrollTop
    	  for(let i = n; i < len; i++) {
    	    let tempSrc = imgs[i].getAttrbute('data-src')
    	    if(imgs[i].offset <= clientHeight + scrollTop ) {
    	      imgs[i].src = tempSrc
    	      n = i // Where is the cache currently loaded
    	    }
    	  }
    	}
    	// Use anti shake optimization
    	list.addEventListenr('scroll', throttle(lazyLoad, 500))
    	
    

The above can be implemented normally. After n = i optimization, it will not execute the loaded before repetition, but for round-trip scrolling, the for loop will still be executed for judgment
You can use the IntersectionObserver of js api. If an element is passed in, it can observe whether the corresponding event will be triggered when it is displayed or moved out of the viewport

/*
  First, create an observation object. The parameters received in the callback are the observed object, which can be multiple, and bind each event
  The intersectionratio of the observed object is a value, which is > 0 when it appears in the viewport, and vice versa
  It can be set that when the loading has been triggered, it will be removed from the observed object
*/
let obser = new IntersectionObserver((imgs) => {
  for(let i = 0; i < imgs.length; i++) {
    let img = imgs[i]
    if(img.inersectionRatio > 0) {
      img.src = img.getAttrbute('data-src')
      obser.unobserve(img)
    }
  }
})

obser.observe(Array.from(imgs))
  1. webpack related
    Use cache
  • When the resource is not changed, go to the cache directly, and splice the file name with the contentHash value to prevent the content from going to the cache when the content is changed.

  • During babel processing, many compatibility processing codes do not need to be rebuilt. You can turn on babel's cache cacheDirectory: true
    Code compression

    css compression uses the optimizecssasassetswebpackplugin plug-in

    html compression uses html webpack plugin

    js automatic compression in production environment

Keywords: Javascript Front-end

Added by Scropion on Mon, 24 Jan 2022 06:05:05 +0200