Preface
Hello everyone , I'm Lin Sanxin , Speak the most difficult knowledge points in the most easy to understand words It's my motto , Foundation is the premise of advanced It's my first heart
background
When we are doing project performance optimization , Optimize the first screen time It is an unavoidable optimization direction , But how many people have thought about the difference between these two things :
White screen time
First screen time
And what's the difference between the calculation of these two times ? Next, I will tell you about it !
White screen time
What is it? ?
White screen time refers to : The time when the page begins to display content . That is to say : The time when the browser displays the first character or element
How to calculate ?
We just need to know when the browser starts displaying content , That is, the white screen time of the page can be obtained at the end time of the page white screen .
therefore , We usually think that browsers start rendering <body>
Tag or parse <head>
The time of the tag is the time when the white screen of the page ends .
Browser support
performance.timing
<head> <title>Document</title> </head> <script type="text/javascript"> // White screen time end point var firstPaint = Date.now() var start = performance.timing.navigationStart console.log(firstPaint - start) </script>
Browser does not support
performance.timing
<head> <title>Document</title> <script type="text/javascript"> window.start = Date.now(); </script> </head> <script type="text/javascript"> // White screen time end point var firstPaint = Date.now() console.log(firstPaint - window.start) </script>
First screen time
What is it? ?
The first screen time is when the user opens the website , The time until the first screen of the browser is rendered . For the user experience , The first screen time is an important factor for users to experience a website .
Why not just use the lifecycle ?
Some of them will say : Why not directly in App.vue Of mounted
Calculate time in the life cycle ? You can see that , Official website said mounted
Execution does not mean that all elements on the first screen have been loaded , therefore mounted
The calculated time will be shorter .
Why not use it directly nextTick?
nextTick
When it comes back , First screen DOM It's all rendered , But calculation First screen time
You don't have to render everything DOM, So the calculated time will be longer
How to calculate ?
We need to use MutationObserver
monitor DOM The change of , Monitor every time DOM Changing fraction , The calculation rule is :
(1 + The layer number * 0.5), Let me give you an example :
<body>
<div>
<div>1</div>
<div>2</div>
</div>
</body>
above DOM The score of the structure is :
1.5 + 2 + 2.5 + 2.5 = 8.5( branch )
In fact, during the loading of the first screen , It will involve DOM An increase in 、 modify 、 Delete , So it will trigger many times MutationObserver
, So we will count the number of different stages score, We put these score Stored in an array observerData
in , The back is very useful
First screen time practice
Now let's start calculating the first screen time !
Lead to
index.html
:html page<!DOCTYPE html> <html lang="en"> <head> </head> <body> <div> <div> <div>1</div> <div>2</div> </div> <div>3</div> <div>4</div> </div> <ul id="ulbox"></ul> </body> <script src="./computed.js"></script> <script src="./request.js"></script> </html>
computed.js
: File for calculating the first screen timeconst observerData = [] let observer = new MutationObserver(() => { // Calculate every time DOM When modifying , The time before the page starts loading const start = window.performance.timing.navigationStart const time = new Date().getTime() - start const body = document.querySelector('body') const score = computedScore(body, 1) // Add to array observerData in observerData.push({ score, time }) }) observer.observe( document, { childList: true, subtree: true } ) function computedScore(element, layer) { let score = 0 const tagName = element.tagName // Exclude these labels if ( tagName !== 'SCRIPT' && tagName !== 'STYLE' && tagName !== 'META' && tagName !== 'HEAD' ) { const children = element.children if (children && children.length) { // Recursively calculate the score for (let i = 0; i < children.length; i++) { score += computedScore(children[i], layer + 1) } } score += 1 + 0.5 * layer } return score }
request.js
: Simulation request modification DOM// Simulation request list const requestList = () => { return new Promise((resolve) => { setTimeout(() => { resolve( [1, 2, 3, 4, 5, 6, 7, 8, 9 ] ) }, 1000) }) } const ulbox = document.getElementById('ulbox') // Simulation request data rendering list const renderList = async () => { const list = await requestList() const fragment = document.createDocumentFragment() for (let i = 0; i < list.length; i++) { const li = document.createElement('li') li.innerText = list[i] fragment.appendChild(li) } ulbox.appendChild(fragment) } // Simulate minor changes to the list const addList = async () => { const li = document.createElement('li') li.innerText = ' Add ' ulbox.appendChild(li) } (async () => { // Simulation request data rendering list await renderList() // Simulate minor changes to the list addList() })()
observerData
When we are all ready to run the code , We got observerData
, Let's see what it looks like ?
Calculate the first screen time
How do we base it observerData
To calculate the first screen time ? We can do that : The first screen time is the time when the next score increases the most than the last score
A lot of people will ask , Why not take the time of the last item as the first screen time ? We should pay attention to : The first screen is not all DOM Render all , Let me take the code just now as an example , We finished rendering the list , Then add another one li, Which time period do you think is the first screen ? It should be the first screen after rendering the list , Because only one has been added li, Small increase in scores , Negligible
So let's start calculating :
const observerData = []
let observer = new MutationObserver(() => {
// Calculate every time DOM When modifying , The time before the page starts loading
const start = window.performance.timing.navigationStart
const time = new Date().getTime() - start
const body = document.querySelector('body')
const score = computedScore(body, 1)
observerData.push({
score,
time
})
// complete Time to call unmountObserver
if (document.readyState === 'complete') {
// Only calculate 10 Seconds rendering time
unmountObserver(10000)
}
})
observer.observe(
document, {
childList: true,
subtree: true
}
)
function computedScore(element, layer) {
let score = 0
const tagName = element.tagName
// Exclude these labels
if (
tagName !== 'SCRIPT' &&
tagName !== 'STYLE' &&
tagName !== 'META' &&
tagName !== 'HEAD'
) {
const children = element.children
if (children && children.length) {
// Recursively calculate the score
for (let i = 0; i < children.length; i++) {
score += computedScore(children[i], layer + 1)
}
}
score += 1 + 0.5 * layer
}
return score
}
// Calculate the first screen time
function getFirstScreenTime() {
let data = null
for (let i = 1; i < observerData.length; i++) {
// Calculate the amplitude
const differ = observerData[i].score - observerData[i - 1].score
// Take the maximum amplitude , Record the corresponding time
if (!data || data.rate <= differ) {
data = {
time: observerData[i].time,
rate: differ
}
}
}
return data
}
let timer = null
function unmountObserver(delay) {
if (timer) return
timer = setTimeout(() => {
// Output the first screen time
console.log(getFirstScreenTime())
// End MutationObserver Monitoring of
observer.disconnect()
observer = null
clearTimeout(timer)
}, delay)
}
Calculate the first screen time 1020ms
summary
My calculation method actually has many flaws , The deletion of elements is not taken into account , But I want you to know how to calculate the first screen time , That's the most important thing , I hope you can understand this calculation idea
Conclusion
I'm Lin Sanxin , An enthusiastic front-end rookie programmer . If you make progress , Like the front , Want to learn the front end , Then we can make friends , Fish together, ha ha , Fish schools , Add me, please note 【 Think no 】