当前位置:网站首页>DOM -- page rendering, style attribute operation, preloading and lazy loading, anti shake and throttling

DOM -- page rendering, style attribute operation, preloading and lazy loading, anti shake and throttling

2022-07-28 07:02:00 Hahaha~

One 、 Rendering of the page

( One ) The browser loads a HTML Loading process of documents

  1、 Put the label 、 Text 、 notes 、 Properties, etc html The code is parsed into a node tree (DOM Tree)
  2、 Put all styles (css Code and browser comes with ) Resolve to structure
  3、 hold css The style structure is combined with the node tree to become a presentation tree / Render tree (Render Tree)
  4、 According to the rendering tree Render Tree Draw page

 

( Two ) Redraw with backflow

 1) backflow :

  • When render tree Because of the number of elements 、 Layout 、 Hiding and other changes that need to be rebuilt is called backflow or backtracking  
  • Each page needs at least one reflow, that is, when the page is first loaded

  2) Repaint :

  • When render tree Some of the elements in the , These attributes only affect the appearance of the element 、 style 、 Styles that do not affect the layout are called redrawing

  3) Relationship :

  • Any right render tree The operation of elements in will cause reflow or redrawing
  • Reflow must cause redrawing Redrawing does not necessarily cause reflow

  4) Common reflow and redraw operations :

  1. Add or remove elements ( backflow + Repaint )
  2. Hidden elements : Such as display:none( backflow + Repaint )    visibility:hidden( Redraw only , No reflow )
  3. Move elements : Such as change top,left(jquery Of animate The way is , change top,left It doesn't necessarily affect the return flow ), Or move elements to something else 1 Of the parent elements ( Repaint + backflow )
  4. Yes style The operation of ( Operate on different properties , The impact is different )
  5. User's operation : Such as changing the size of browser or browser font ( backflow + Repaint )

      Example :

 <style>
        .box {
            width: 200px;
            height: 200px;
            background-color: red;
            /* visibility: hidden; */
            /* display: none; */
        }
    </style>
    <div class="box">hello</div>
    <button onclick="fn()">change</button>
    <script>
        function fn() {
            var box = document.querySelector(".box")
            box.innerHTML = "6666" // Changed the result reflow of the document tree 
            box.style.visibility = "hidden"; // Elements are just hidden   Position reserved  => Redraw without reflow 
            box.style.display = "none"; // The element will disappear   Its position will not be preserved in the document tree  => backflow 
        }
    </script>

  5) influence :

  • Frequent redrawing / Reflux will cause Computer consumption is too high It leads to poor performance and user experience of the page  

  6) terms of settlement :

  • Try to avoid redrawing
  • Create a fragment   

fragment:

Add content to fragment Inside It itself is not added to the document tree for rendering   After adding the contents to the document tree, it will disappear That is, the child element to be added ---> Added to the fragment---> take fragment Add to the target parent element ---> The child element enters the parent element ,fragment disappear ( Redraw only 、 Reflux once ) 

stay dom It's called in Chinese => fragment   In the wechat applet => block    stay vue in => template    stay react in => </>

   Case study : add to 1 Ten thousand squares on the page Each grid shows the time (ms)

<style>
#box td {
      border: 1px gainsboro solid;
 }
</style>
<table id="box">
</table>
<script>
 let tb=document.querySelector(".box")
        for(let i=0;i<100;i++){
        	let tr=document.createElement("tr")
        	tb.appendChild(tr)         // Add elements to the document tree multiple times   Lead to frequent reflow and redrawing 
        	for(let j=0;j<100;j++){
        		let dt=new Date().getTime()
        		let td=document.createElement("td")
        		td.innerHTML=dt
        		tr.appendChild(td)      // Add elements to the document tree multiple times   Lead to frequent reflow and redrawing 
        	}
        }
      // Multiple reflow redraws 
</script>

    Optimize :

 <style>
        #box td {
            border: 1px gainsboro solid;
        }
</style>
<table id="box"></table>
<script>
     // Create a fragment Element to host the element to be rendered 
        let tb=document.querySelector("#box")
        let fra1=document.createDocumentFragment() // It's in memory, not in the document 
        for(let i=0;i<100;i++){
        	let tr=document.createElement("tr")
        	fra1.appendChild(tr)
        	for(let j=0;j<100;j++){
        		let dt=new Date().getTime()
        		let td=document.createElement("td")
        		td.innerHTML=dt
        		tr.appendChild(td)
        	}
        }
      tb.appendChild(fra1) // It will not be added to the document tree itself for rendering   But its descendants will be added 
    // Added to the document tree only once   So only reflux 1 Time 
</script>

Two 、style The operation of

( One ) The problem of getting elements

    Cited example :

<style>
    .box {
            width: 400px;
            height: 300px;
            background-color: aqua;
            cursor: pointer;
        }
</style>
<div class="box" style="color: red;"> This is a div1</div>
<script>
var body1 = document.body
var box2 = document.querySelector(".box2")
var color1 = document.querySelector(".box").style.color
var width1 = document.querySelector(".box").style.width
console.log(body1)   //body
console.log(box2)    //null  The node has not been loaded   Can't access the back 
console.log(color1)  //red
console.log(width1)  //     Nothing is empty 
</script>
<div class="box2"> This is a div2</div>

  Print the results :

 

reflection : Why? div2 yes null?

  reason :

  • I can't get it script Element node loaded after script node , Because documents are loaded in the order of the document tree

  Solution : 

  • Scheme 1 : When the page is loaded, the event is triggered Then go to the method of obtaining nodes
    function fn() {
       var box2 = document.querySelector(".box2")
       console.log(box2)
    }
    window.onload = fn  
//window.onload It will be executed after the page is loaded   namely fn Also execute after the page is loaded   You can access div2
  • Option two : By introducing script Labeled defer、async( modification src Load external js Resources ) Asynchronous properties

                      Write the code externally js In file

//index.js  In file :
<script>
var box2 = document.querySelector(".box2")
console.log(box2)
</script>
//html In file :
<script defer src="index.js"></script>
<div class="box2"> This is a div2</div>

async and defer
Asynchronous loading of scripts
1.<script src="script.js"></script>
No,  defer  or  async, The browser loads and executes the specified script immediately ,“ immediately ” It means rendering the  script  Before the document element under the tag , That is, not waiting for subsequent document elements to load , Load and execute as soon as you read it .

2.<script async src="script.js"></script>
Yes  async, The process of loading and rendering subsequent document elements will follow  script.js  Load and execute in parallel ( asynchronous ).

3.<script defer src="myscript.js"></script>
Yes  defer, The process of loading subsequent document elements will be the same as  script.js  The loading is done in parallel ( asynchronous ), however  script.js  After all elements are parsed ,DOMContentLoaded  Before the event triggers .

From a practical point of view : First, throw all the scripts into  </body>  It was best practice before , Because it's the only optimization option for old browsers , This method can ensure that all other non script elements can be loaded and parsed with the fastest speed .
 

 

( Two )style Attribute problem

   1. Inline style  :el.style.xx    ele.currentStyle (IE Lower version of )

  • You can only manipulate inline styles No compatibility issues  
  • Can only be set to string   The style must use hump nomenclature  
  • Encountered the same style as reserved words , It should be preceded by “css”(eg:float—>el.style.cssFloat)
  • In fact, it is the attribute value of the element in the obtained document tree

  2. Final drawing style :window.getComputedStyle(el)

  •   In fact, it is the attribute value of the element in the rendering tree

  3. expand :window.getComputedStyle(ele,"after")

  • The second parameter is to get the pseudo element style

3、 ... and 、 Anti shake and throttling

1) Shake proof :

  •    After triggering a high frequency event n The function will only execute once per second , If n High frequency events are triggered again within seconds , Then recalculate the time
  •   Ideas : Every time an event is triggered, the previous delay call method is cancelled

  Case study :

document.onclick = fangdou(function(e) {
    	console.log(6666)
    }, 1000)
    function fangdou(cb, delay) {
    	var timer = null;
    	return function() {
    		//return This function has a high frequency    Find a way to make cb() Slow down the execution : Shake proof 
    		clearTimeout(timer)
    		timer = setTimeout(function() {
    			cb()
    		}, delay)
    	}
    }

  Optimize :

document.onclick = fangdou2(function(e) {
        console.log(6666,e,this)
    }, 1000)
    
    function fangdou2(cb, delay) {
        var timer = null;
        return function() {
            //return This function has a high frequency    Find a way to make cb() Slow down the execution : Shake proof 
            let arg=arguments
            clearTimeout(timer)
            timer = setTimeout(()=>{
                cb.apply(this,arg)
            }, delay)
        }
    }


2) throttle :

  • High frequency events trigger , But in n Only once per second , So throttling dilutes the frequency of function execution
  • Ideas : Every time an event is triggered, it is judged whether there is a delay function waiting for execution

Case study :

document.onmousemove=jieliu(function(){console.log(666)},20)
    function jieliu(cb,daley){
    	var timer=null;
    	return function(){
    		if(!timer){
    		  timer=setTimeout(()=>{
    			  cb();						  
    			  timer=null
    		  },daley)						
    		}
    	}
    }

Optimize :

function jieliu2(cb,daley){
        var timer=null;
        return function(){
            // console.log(66666,timer)
            // this Is an event function this
            let arg=arguments
            if(!timer){
              timer=setTimeout(()=>{
                  cb.apply(this,arg); // It was originally window But the hope is cb					  
                  timer=null
              },daley)						
            }
        }
    }

Four 、 Preloading and lazy loading

1) Preloading : Load resources ahead of time -- Optimization of homologous loading

  Case study :

  • After loading the same image once, it will be saved in the browser's local , Don't load more than once
<!--  Load three identical pictures at the same time -->
<img src="https://img2.baidu.com/it/u=1814268193,3619863984&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1658422800&t=d974afe62dd1225c4faa14b1538bf7f5">		
<img src="https://img2.baidu.com/it/u=1814268193,3619863984&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1658422800&t=d974afe62dd1225c4faa14b1538bf7f5">		
<img src="https://img2.baidu.com/it/u=1814268193,3619863984&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1658422800&t=d974afe62dd1225c4faa14b1538bf7f5">

  effect : 

2) Lazy loading : Don't load it yet Wait until a certain condition is true before loading resources

  Case study

  • When the condition is true, the image under the page is loaded Make sure that it is loaded when you slide to the image position Can see the picture
<p>hello</p><p>hello</p><p>hello</p><p>hello</p><p>hello</p>
<p>hello</p><p>hello</p><p>hello</p><p>hello</p><p>hello</p>
<!-- Many are omitted here p label -->
<p>hello</p><p>hello</p><p>hello</p><p>hello</p><p>hello</p>
<p>hello</p><p>hello</p><p>hello</p><p>hello</p><p>hello</p>
<script>
window.onload=function(){
  document.onscroll=function(e){
	let top=window.pageYOffset||document.body.scrollTop||document.documentElement.scrollTop
	let h=cHeight =window.innerHeight||document.body.clientHeight;
	console.log(top,img2.offsetTop-h-100)
	if(top>=(img2.offsetTop-h-100)){
			img2.src=img2.dataset.src1  // If the condition is true, load the picture 
	}
  }
}			
</script>
<img  id="img2" data-src1="https://img1.baidu.com/it/u=1966616150,2146512490&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1658422800&t=f99225a791b634226dcd5ee47c8b5f3f">

  effect :

 

原网站

版权声明
本文为[Hahaha~]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/209/202207280517074306.html