偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

首屏?xí)r間,你說你優(yōu)化了,那你倒是計算出來給我看??!

開發(fā) 前端
我們只需要知道瀏覽器開始顯示內(nèi)容的時間點,即頁面白屏結(jié)束時間點即可獲取到頁面的白屏?xí)r間。因此,我們通常認(rèn)為瀏覽器開始渲染<body>標(biāo)簽或者解析完<head>標(biāo)簽的時刻就是頁面白屏結(jié)束的時間點。

前言

大家好,我是林三心,用最通俗易懂的話講最難的知識點是我的座右銘,基礎(chǔ)是進(jìn)階的前提是我的初心

背景

當(dāng)我們在做項目的性能優(yōu)化的時候,優(yōu)化首屏?xí)r間是一個避不過去的優(yōu)化方向,但是又有多少人想過這兩個東西的區(qū)別呢:

  • 白屏?xí)r間
  • 首屏?xí)r間

并且這兩個時間的計算方式又有什么區(qū)別呢?接下來我就給大家講一下吧!

白屏?xí)r間

是什么?

白屏?xí)r間指的是:頁面開始顯示內(nèi)容的時間。也就是:瀏覽器顯示第一個字符或者元素的時間

圖片圖片

怎么算?

我們只需要知道瀏覽器開始顯示內(nèi)容的時間點,即頁面白屏結(jié)束時間點即可獲取到頁面的白屏?xí)r間。

因此,我們通常認(rèn)為瀏覽器開始渲染<body>標(biāo)簽或者解析完<head>標(biāo)簽的時刻就是頁面白屏結(jié)束的時間點。

  • 瀏覽器支持performance.timing
<head>
  <title>Document</title>
</head>
<script type="text/javascript">
  // 白屏?xí)r間結(jié)束點
  var firstPaint = Date.now()
  var start = performance.timing.navigationStart
  console.log(firstPaint - start)
</script>
  • 瀏覽器不支持performance.timing
<head>
  <title>Document</title>
  <script type="text/javascript">
    window.start = Date.now();
  </script>
</head>
<script type="text/javascript">
  // 白屏?xí)r間結(jié)束點
  var firstPaint = Date.now()
  console.log(firstPaint - window.start)
</script>

首屏?xí)r間

是什么?

首屏?xí)r間是指用戶打開網(wǎng)站開始,到瀏覽器首屏內(nèi)容渲染完成的時間。對于用戶體驗來說,首屏?xí)r間是用戶對一個網(wǎng)站的重要體驗因素。

圖片圖片

為什么不直接用生命周期?

有些小伙伴會說:為啥不直接在App.vue的mounted生命周期里計算時間呢?大家可以看看,官網(wǎng)說了mounted執(zhí)行并不代表首屏所有元素加載完畢,所以mounted計算出來的時間會偏短。

圖片圖片

為什么不直接用nextTick?

nextTick回調(diào)的時候,首屏的DOM都渲染出來了,但是計算首屏?xí)r間并不需要渲染所有DOM,所以計算出來的時間會偏長

怎么算?

我們需要利用MutationObserver監(jiān)控DOM的變化,監(jiān)控每一次DOM變化的分?jǐn)?shù),計算的規(guī)則為: (1 + 層數(shù) * 0.5),我舉個例子:

<body>
    <div>
      <div>1</div>
      <div>2</div>
    </div>
</body>

以上DOM結(jié)構(gòu)的分?jǐn)?shù)為:

1.5 + 2 + 2.5 + 2.5 = 8.5(分)

圖片圖片

其實在首屏的加載中,會涉及到DOM的增加、修改、刪除,所以會觸發(fā)多次MutationObserver,所以會統(tǒng)計出不同階段的score,我們把這些score存放在一個數(shù)組observerData中,后面大有用處

首屏?xí)r間實踐

現(xiàn)在我們開始計算首屏?xí)r間吧!

前置準(zhǔn)備

  • index.html:html頁面
<!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:計算首屏?xí)r間的文件
const observerData = []

let observer = new MutationObserver(() => {
  // 計算每次DOM修改時,距離頁面剛開始加載的時間
  const start = window.performance.timing.navigationStart
  const time = new Date().getTime() - start
  
  const body = document.querySelector('body')
  const score = computedScore(body, 1)
  // 加到數(shù)組 observerData 中
  observerData.push({
    score,
    time
  })
})
observer.observe(
  document, {
    childList: true,
    subtree: true
  }
)

function computedScore(element, layer) {
  let score = 0
  const tagName = element.tagName
  // 排除這些標(biāo)簽的情況
  if (
    tagName !== 'SCRIPT' &&
    tagName !== 'STYLE' &&
    tagName !== 'META' &&
    tagName !== 'HEAD'
  ) {
    const children = element.children
    if (children && children.length) {
      // 遞歸計算分?jǐn)?shù)
      for (let i = 0; i < children.length; i++) {
        score += computedScore(children[i], layer + 1)
      }
    }

    score += 1 + 0.5 * layer
  }
  return score
}
  • request.js:模擬請求修改DOM
// 模擬請求列表
const requestList = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(
        [1, 2, 3,
          4, 5, 6,
          7, 8, 9
        ]
      )
    }, 1000)
  })
}

const ulbox = document.getElementById('ulbox')

// 模擬請求數(shù)據(jù)渲染列表
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)
}

// 模擬對列表進(jìn)行輕微修改
const addList = async () => {
  const li = document.createElement('li')
  li.innerText = '加上去'
  ulbox.appendChild(li)
}

(async () => {
  // 模擬請求數(shù)據(jù)渲染列表
  await renderList()
  // 模擬對列表進(jìn)行輕微修改
  addList()
})()

observerData

當(dāng)我們一切準(zhǔn)備就緒后運行代碼,我們獲得了observerData,我們看看它長什么樣?

計算首屏?xí)r間

我們怎么根據(jù)observerData來計算首屏?xí)r間呢?我們可以這么算:下次分?jǐn)?shù)比上次分?jǐn)?shù)增加幅度最大的時間作為首屏?xí)r間

很多人會問了,為什么不是取最后一項的時間來當(dāng)做首屏?xí)r間呢?大家要注意了:首屏并不是所有DOM都渲染,我就拿剛剛的代碼來舉例吧,我們渲染完了列表,然后再去增加一個li,那你是覺得哪個時間段算是首屏呢?應(yīng)該是渲染完列表后算首屏完成,因為后面只增加了一個li,分?jǐn)?shù)的漲幅較小,可以忽略不計

所以我們開始計算吧:

const observerData = []

let observer = new MutationObserver(() => {
  // 計算每次DOM修改時,距離頁面剛開始加載的時間
  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時去調(diào)用 unmountObserver
  if (document.readyState === 'complete') {
    // 只計算10秒內(nèi)渲染時間
    unmountObserver(10000)
  }
})
observer.observe(
  document, {
    childList: true,
    subtree: true
  }
)

function computedScore(element, layer) {
  let score = 0
  const tagName = element.tagName
  // 排除這些標(biāo)簽的情況
  if (
    tagName !== 'SCRIPT' &&
    tagName !== 'STYLE' &&
    tagName !== 'META' &&
    tagName !== 'HEAD'
  ) {
    const children = element.children
    if (children && children.length) {
      // 遞歸計算分?jǐn)?shù)
      for (let i = 0; i < children.length; i++) {
        score += computedScore(children[i], layer + 1)
      }
    }

    score += 1 + 0.5 * layer
  }
  return score
}

// 計算首屏?xí)r間
function getFirstScreenTime() {
  let data = null
  for (let i = 1; i < observerData.length; i++) {
    // 計算幅度
    const differ = observerData[i].score - observerData[i - 1].score
    // 取最大幅度,記錄對應(yīng)時間
    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(() => {
    // 輸出首屏?xí)r間
    console.log(getFirstScreenTime())
    // 終止MutationObserver的監(jiān)控
    observer.disconnect()
    observer = null
    clearTimeout(timer)
  }, delay)
}

計算出首屏?xí)r間1020ms

總結(jié)

我這個計算方法其實很多漏洞,沒把刪除元素也考慮進(jìn)去,但是想讓大家知道計算首屏?xí)r間的計算思想,這才是最重要的,希望大家能理解這個計算思想。

責(zé)任編輯:武曉燕 來源: 前端之神
相關(guān)推薦

2021-08-11 07:55:10

Go內(nèi)置函數(shù)

2022-02-24 07:56:27

Linux系統(tǒng)ELF

2021-02-14 14:06:24

SQL數(shù)據(jù)庫面試

2015-06-25 10:57:15

推薦系統(tǒng)老婆算出來

2009-11-06 13:54:09

Visual Stud

2022-07-14 08:22:48

Computedvue3

2021-11-09 14:08:45

DockerDockerfileJava

2021-03-01 10:38:13

深度學(xué)習(xí)編程人工智能

2011-08-24 13:32:56

CREATE TABL中文man

2020-03-16 10:42:23

大數(shù)據(jù)IT工具

2020-03-25 10:44:16

位運算操作技巧

2023-11-08 08:09:36

幾何算法解析幾何

2023-05-08 00:01:29

數(shù)據(jù)分析指標(biāo)標(biāo)簽

2024-12-26 11:49:14

2009-09-10 16:22:48

LINQ建立數(shù)據(jù)報表

2023-12-08 13:16:00

CSSJSXStyleX

2025-07-01 01:55:00

Redis集群模式

2022-10-12 00:07:25

加密貨幣區(qū)塊鏈比特幣

2012-04-25 22:58:36

2018-03-19 10:39:28

Java序列化對象
點贊
收藏

51CTO技術(shù)棧公眾號